GWT CellTable Custom Number Cell - gwt

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);
}
}
}

Related

How to re-render a specific node in gwt cell tree

I am implementing a directory structure like Windows Explorer. I want to re-render a specific node of tree after any folder operations is done such as add folder, remove folder... etc
private ListDataProvider<Object> dataProvider= new ListDataProvider<Object>();
private Object current;//store object of currentNode;
private Map<Object, ListDataProvider<Object>> keyprovider =
new HashMap<Object,ListDataProvider<Object>>();
private CellTree tree;
// keeps a map for storing dataproviders in each hierarchy ,
public void setListToCurrentNode(List<Object> newList){
//adding this newlist to current data provider not reflecting to display
keyprovider.get(currentObject).setList(newList);
}
public void onModuleLoad(){
treeSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
public void onSelectionChange(SelectionChangeEvent event) {
//setting current object as selected node
current = treeSelectionModel.getSelectedObject();
}
});
}
Data providers force to re-render corresponding DOM. Code below demonstrates how it works.
This example generates 2-leveled tree, where you can refresh (re-generate) leaf nodes by pressing Enter key on selected root node.
I tried to keep code as simple as possible, all needed stuff contained right here.
public class TestEntryPoint implements EntryPoint {
private static final Logger LOG = Logger.getLogger(TestEntryPoint.class.getName());
class Item {
String name;
boolean leaf;
public Item(String name, boolean leaf) {
this.name = name;
this.leaf = leaf;
}
#Override
public String toString() {
return "Item {name=" + name + ", leaf=" + leaf + "}";
}
}
class ItemCell extends AbstractCell<Item> {
public ItemCell() {
super("keydown");
}
#Override
public void render(Context context, Item value, SafeHtmlBuilder sb) {
if (value != null) sb.appendEscaped(value.name);
}
#Override
protected void onEnterKeyDown(
Context context, Element parent, Item value, NativeEvent event, ValueUpdater<Item> valueUpdater) {
LOG.info("ItemCell.onEnterKeyDown: value=" + value);
if (value == null || value.leaf) return;
ListDataProvider<Item> leafDataProvider = leafDataProviders.get(value.name);
if (leafDataProvider == null) return;
// -->> Here we generate new childs of selected root node
leafDataProvider.setList(generateLeafs());
}
}
class ItemTreeViewModel implements TreeViewModel {
#Override
public <T> NodeInfo<?> getNodeInfo(T value) {
return new DefaultNodeInfo<Item>(
value == null ? rootDataProvider : leafDataProviders.get(((Item) value).name),
new ItemCell());
}
#Override
public boolean isLeaf(Object value) {
return (value instanceof Item) && ((Item) value).leaf;
}
}
private int id = 0;
private CellTree cellTree;
private ListDataProvider<Item> rootDataProvider;
private Map<String, ListDataProvider<Item>> leafDataProviders = new HashMap<String, ListDataProvider<Item>>();
private List<Item> generateLeafs() {
List<Item> leafList = new ArrayList<Item>(5);
for (int j = 0; j < 5; ++j)
leafList.add(new Item("Leaf Item " + (++id), true));
return leafList;
}
public void onModuleLoad() {
List<Item> rootList = new ArrayList<Item>(10);
for (int i = 0; i < 10; ++i) {
Item rootItem = new Item("Root Item " + (++id), false);
rootList.add(rootItem);
leafDataProviders.put(rootItem.name, new ListDataProvider<Item>(generateLeafs()));
}
rootDataProvider = new ListDataProvider<Item>(rootList);
cellTree = new CellTree(new ItemTreeViewModel(), null);
cellTree.setAnimationEnabled(true);
RootLayoutPanel.get().add(cellTree);
}
}
Solved by Changing Listdataprovider into AsyncDataProvider ,Implementation is below
private final class DataProvider extends AsyncDataProvider<Object> {
private Object value;
private List Objs;
DataProvider(Object value) {
this.value = value;
}
public void update(List objs) {//Call update when you wanted to refresh tree
this.objs=objs;
for (HasData<Object> disp : getDataDisplays()) {
this.onRangeChanged(disp);
break;
}
}
#Override
protected void onRangeChanged(final HasData<Object> display) {
updateRowData(0, objs);
updateRowCount(objs.size(), true);
}

PropertyGrid Browsable not found for entity framework created property, how to find it?

Trying to remove or place items on a property grid by changing the Browsable attribute.
But unless browsable is set on object creation my code to change Browsable doesn't work. Now I can manually add browsable, but when I make a change to my entity (still developing project so lots of changes to entity) any additional attributes I add go away.
I attempted to set [Browsable(true)] two ways other ways: http://ardalis.com/adding-attributes-to-generated-classes and http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/617ebfca-0f68-4b90-83fd-0da758fadbd0/
Both seem to actually set the Browsable correctly, but when I loop thru the Attributes in Property Descriptor it is not there (for me to change).
String fieldname = "browsable"; // I also edit "description"
PropertyDescriptor pd = TypeDescriptor.GetProperties(o.GetType())[propertyName];
object attrib = null;
AttributeCollection attribs = pd.Attributes;
foreach (Attribute a in attribs)
{
if (a.GetType() == attributeType)
{
attrib = a;
break;
}
}
// The microsoft documentation leads one to believe the following line of code would find the desired attribute,
// negating the need for the more complete foreach statement above.
// However, it appears to find attribute even when it does not exist. Setting value for "found" attribute
// will result in random memory being changed, which results in very unpredictable behavior.
// attrib = pd.Attributes[t];
if (attrib != null)
{
// locate field that contains value
FieldInfo field = attrib.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
if (field != null)
{
if (field.FieldType == value.GetType())
{
// set field to desired value
field.SetValue(attrib, value);
}
}
}
else
{
throw new Exception("Attribute (" + attributeType.Name + ") does not exist for Property(" + propertyName + ")");
}
So I keep getting the Exception that I throw if it doesn't find "browsable" - but only if not set in Model.Designer.cs first.
Below is what my Model.Designer.cs looks like.
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
[DataMemberAttribute()]
[Browsable(false)] // this works, but goes away if change my entity
public Nullable<global::System.TimeSpan> SignoutAfter
{
get
{
return _SignoutAfter;
}
set
{
OnSignoutAfterChanging(value);
ReportPropertyChanging("SignoutAfter");
_SignoutAfter = StructuralObject.SetValidValue(value);
ReportPropertyChanged("SignoutAfter");
OnSignoutAfterChanged();
}
}
private Nullable<global::System.TimeSpan> _SignoutAfter;
partial void OnSignoutAfterChanging(Nullable<global::System.TimeSpan> value);
partial void OnSignoutAfterChanged();
So I need a way to either 1. add browsable to entity when I edit them so it is always on perhaps editing the t4, but I don't even know where to begin with that or 2. Another way to add or remove (and edit) the properties (see I might edit the description based on some logic) or 3 find the hole in my code so I can find and edit browsable (description and displayname).
Update The second link above, http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/617ebfca-0f68-4b90-83fd-0da758fadbd0/ , has a lot of what I need, I think. Adding a Attribute array variable to the class and some code to see if that is set seems to have the effect that I am looking for. But leaving this open to find a better answer.
partial class Client : ICustomTypeDescriptor
{
public Attribute[] SignOutAttributes; // added this
#region ICustomTypeDescriptor Members
... // see the link for the other code
public PropertyDescriptorCollection GetProperties (Attribute[] attributes)
{
var propsColl = TypeDescriptor.GetProperties (this, attributes, true);
var props = new List<PropertyDescriptor> ();
foreach (PropertyDescriptor prop in propsColl)
{
String strUPPERCaseName = prop.Name.ToUpper (); // for my thick fingers
// make sure case values are upper case
switch (strUPPERCaseName)
{
case "SIGNOUTAFTER":
if (SignOutAttributes != null)
{
props.Add(new CustomPropertyDescriptor(prop, SignOutAttributes));
}
else
{
props.Add (new CustomPropertyDescriptor (prop, new Attribute[]
{
new CategoryAttribute("Settings"),
new DisplayNameAttribute("Signout After"),
new BrowsableAttribute(true),
new ReadOnlyAttribute(false)
}));
}
break;
default:
props.Add (prop);
break;
}
}
return new PropertyDescriptorCollection (props.ToArray ());
}
In my code I can change the Attribute Array to have what Attribute values I want.
_client.SignOutAttributes = new Attribute[]
{
new CategoryAttribute ("My Category"),
new DisplayNameAttribute("Signout After"),
new BrowsableAttribute(true),
new ReadOnlyAttribute(false)
};
I'm not 100% happy with this. I have to write code for each Property.
Using ICustomTypeDescriptor is definitely the good solution when you want dynamic (set at runtime) properties. Here is generic ICustomTypeDescriptor utility class that I've been using for this sort of property grid hacking, it's pretty straightforward to use:
public sealed class DynamicTypeDescriptor: ICustomTypeDescriptor, INotifyPropertyChanged
{
private Type _type;
private AttributeCollection _attributes;
private TypeConverter _typeConverter;
private Dictionary<Type, object> _editors;
private EventDescriptor _defaultEvent;
private PropertyDescriptor _defaultProperty;
private EventDescriptorCollection _events;
public event PropertyChangedEventHandler PropertyChanged;
private DynamicTypeDescriptor()
{
}
public DynamicTypeDescriptor(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
_type = type;
_typeConverter = TypeDescriptor.GetConverter(type);
_defaultEvent = TypeDescriptor.GetDefaultEvent(type);
_defaultProperty = TypeDescriptor.GetDefaultProperty(type);
_events = TypeDescriptor.GetEvents(type);
List<PropertyDescriptor> normalProperties = new List<PropertyDescriptor>();
OriginalProperties = TypeDescriptor.GetProperties(type);
foreach (PropertyDescriptor property in OriginalProperties)
{
if (!property.IsBrowsable)
continue;
normalProperties.Add(property);
}
Properties = new PropertyDescriptorCollection(normalProperties.ToArray());
_attributes = TypeDescriptor.GetAttributes(type);
_editors = new Dictionary<Type, object>();
object editor = TypeDescriptor.GetEditor(type, typeof(UITypeEditor));
if (editor != null)
{
_editors.Add(typeof(UITypeEditor), editor);
}
editor = TypeDescriptor.GetEditor(type, typeof(ComponentEditor));
if (editor != null)
{
_editors.Add(typeof(ComponentEditor), editor);
}
editor = TypeDescriptor.GetEditor(type, typeof(InstanceCreationEditor));
if (editor != null)
{
_editors.Add(typeof(InstanceCreationEditor), editor);
}
}
public T GetPropertyValue<T>(string name, T defaultValue)
{
if (name == null)
throw new ArgumentNullException("name");
foreach (PropertyDescriptor pd in Properties)
{
if (pd.Name == name)
{
try
{
return (T)Convert.ChangeType(pd.GetValue(Component), typeof(T));
}
catch
{
return defaultValue;
}
}
}
return defaultValue;
}
public void SetPropertyValue(string name, object value)
{
if (name == null)
throw new ArgumentNullException("name");
foreach (PropertyDescriptor pd in Properties)
{
if (pd.Name == name)
{
pd.SetValue(Component, value);
break;
}
}
}
internal void OnValueChanged(PropertyDescriptor prop)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(prop.Name));
}
}
internal static T GetAttribute<T>(AttributeCollection attributes) where T : Attribute
{
if (attributes == null)
return null;
foreach (Attribute att in attributes)
{
if (typeof(T).IsAssignableFrom(att.GetType()))
return (T)att;
}
return null;
}
public sealed class DynamicProperty: PropertyDescriptor, INotifyPropertyChanged
{
private readonly Type _type;
private readonly bool _hasDefaultValue;
private readonly object _defaultValue;
private readonly PropertyDescriptor _existing;
private readonly DynamicTypeDescriptor _descriptor;
private Dictionary<Type, object> _editors;
private bool? _readOnly;
private bool? _browsable;
private string _displayName;
private string _description;
private string _category;
private List<Attribute> _attributes = new List<Attribute>();
public event PropertyChangedEventHandler PropertyChanged;
internal DynamicProperty(DynamicTypeDescriptor descriptor, Type type, object value, string name, Attribute[] attrs)
: base(name, attrs)
{
_descriptor = descriptor;
_type = type;
Value = value;
DefaultValueAttribute def = DynamicTypeDescriptor.GetAttribute<DefaultValueAttribute>(Attributes);
if (def == null)
{
_hasDefaultValue = false;
}
else
{
_hasDefaultValue = true;
_defaultValue = def.Value;
}
if (attrs != null)
{
foreach (Attribute att in attrs)
{
_attributes.Add(att);
}
}
}
internal static Attribute[] GetAttributes(PropertyDescriptor existing)
{
List<Attribute> atts = new List<Attribute>();
foreach (Attribute a in existing.Attributes)
{
atts.Add(a);
}
return atts.ToArray();
}
internal DynamicProperty(DynamicTypeDescriptor descriptor, PropertyDescriptor existing, object component)
: this(descriptor, existing.PropertyType, existing.GetValue(component), existing.Name, GetAttributes(existing))
{
_existing = existing;
}
public void RemoveAttributesOfType<T>() where T : Attribute
{
List<Attribute> remove = new List<Attribute>();
foreach (Attribute att in _attributes)
{
if (typeof(T).IsAssignableFrom(att.GetType()))
{
remove.Add(att);
}
}
foreach (Attribute att in remove)
{
_attributes.Remove(att);
}
}
public IList<Attribute> AttributesList
{
get
{
return _attributes;
}
}
public override AttributeCollection Attributes
{
get
{
return new AttributeCollection(_attributes.ToArray());
}
}
public object Value { get; set; }
public override bool CanResetValue(object component)
{
if (_existing != null)
return _existing.CanResetValue(component);
return _hasDefaultValue;
}
public override Type ComponentType
{
get
{
if (_existing != null)
return _existing.ComponentType;
return typeof(object);
}
}
public override object GetValue(object component)
{
if (_existing != null)
return _existing.GetValue(component);
return Value;
}
public override string Category
{
get
{
if (_category != null)
return _category;
return base.Category;
}
}
public void SetCategory(string category)
{
_category = category;
}
public override string Description
{
get
{
if (_description != null)
return _description;
return base.Description;
}
}
public void SetDescription(string description)
{
_description = description;
}
public override string DisplayName
{
get
{
if (_displayName != null)
return _displayName;
if (_existing != null)
return _existing.DisplayName;
return base.DisplayName;
}
}
public void SetDisplayName(string displayName)
{
_displayName = displayName;
}
public override bool IsBrowsable
{
get
{
if (_browsable.HasValue)
return _browsable.Value;
return base.IsBrowsable;
}
}
public void SetBrowsable(bool browsable)
{
_browsable = browsable;
}
public override bool IsReadOnly
{
get
{
if (_readOnly.HasValue)
return _readOnly.Value;
if (_existing != null)
return _existing.IsReadOnly;
ReadOnlyAttribute att = DynamicTypeDescriptor.GetAttribute<ReadOnlyAttribute>(Attributes);
if (att == null)
return false;
return att.IsReadOnly;
}
}
public void SetIsReadOnly(bool readOnly)
{
_readOnly = readOnly;
}
public override Type PropertyType
{
get
{
if (_existing != null)
return _existing.PropertyType;
return _type;
}
}
public override void ResetValue(object component)
{
if (_existing != null)
{
_existing.ResetValue(component);
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(Name));
}
_descriptor.OnValueChanged(this);
return;
}
if (CanResetValue(component))
{
Value = _defaultValue;
_descriptor.OnValueChanged(this);
}
}
public override void SetValue(object component, object value)
{
if (_existing != null)
{
_existing.SetValue(component, value);
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(Name));
}
_descriptor.OnValueChanged(this);
return;
}
Value = value;
_descriptor.OnValueChanged(this);
}
public override bool ShouldSerializeValue(object component)
{
if (_existing != null)
return _existing.ShouldSerializeValue(component);
return false;
}
public override object GetEditor(Type editorBaseType)
{
if (editorBaseType == null)
throw new ArgumentNullException("editorBaseType");
if (_editors != null)
{
object type;
if ((_editors.TryGetValue(editorBaseType, out type)) && (type != null))
return type;
}
return base.GetEditor(editorBaseType);
}
public void SetEditor(Type editorBaseType, object obj)
{
if (editorBaseType == null)
throw new ArgumentNullException("editorBaseType");
if (_editors == null)
{
if (obj == null)
return;
_editors = new Dictionary<Type, object>();
}
if (obj == null)
{
_editors.Remove(editorBaseType);
}
else
{
_editors[editorBaseType] = obj;
}
}
}
public PropertyDescriptor AddProperty(Type type, string name, object value, string displayName, string description, string category, bool hasDefaultValue, object defaultValue, bool readOnly)
{
return AddProperty(type, name, value, displayName, description, category, hasDefaultValue, defaultValue, readOnly, null);
}
public PropertyDescriptor AddProperty(
Type type,
string name,
object value,
string displayName,
string description,
string category,
bool hasDefaultValue,
object defaultValue,
bool readOnly,
Type uiTypeEditor)
{
if (type == null)
throw new ArgumentNullException("type");
if (name == null)
throw new ArgumentNullException("name");
List<Attribute> atts = new List<Attribute>();
if (!string.IsNullOrEmpty(displayName))
{
atts.Add(new DisplayNameAttribute(displayName));
}
if (!string.IsNullOrEmpty(description))
{
atts.Add(new DescriptionAttribute(description));
}
if (!string.IsNullOrEmpty(category))
{
atts.Add(new CategoryAttribute(category));
}
if (hasDefaultValue)
{
atts.Add(new DefaultValueAttribute(defaultValue));
}
if (uiTypeEditor != null)
{
atts.Add(new EditorAttribute(uiTypeEditor, typeof(UITypeEditor)));
}
if (readOnly)
{
atts.Add(new ReadOnlyAttribute(true));
}
DynamicProperty property = new DynamicProperty(this, type, value, name, atts.ToArray());
AddProperty(property);
return property;
}
public void RemoveProperty(string name)
{
if (name == null)
throw new ArgumentNullException("name");
List<PropertyDescriptor> remove = new List<PropertyDescriptor>();
foreach (PropertyDescriptor pd in Properties)
{
if (pd.Name == name)
{
remove.Add(pd);
}
}
foreach (PropertyDescriptor pd in remove)
{
Properties.Remove(pd);
}
}
public void AddProperty(PropertyDescriptor property)
{
if (property == null)
throw new ArgumentNullException("property");
Properties.Add(property);
}
public override string ToString()
{
return base.ToString() + " (" + Component + ")";
}
public PropertyDescriptorCollection OriginalProperties { get; private set; }
public PropertyDescriptorCollection Properties { get; private set; }
public DynamicTypeDescriptor FromComponent(object component)
{
if (component == null)
throw new ArgumentNullException("component");
if (!_type.IsAssignableFrom(component.GetType()))
throw new ArgumentException(null, "component");
DynamicTypeDescriptor desc = new DynamicTypeDescriptor();
desc._type = _type;
desc.Component = component;
// shallow copy on purpose
desc._typeConverter = _typeConverter;
desc._editors = _editors;
desc._defaultEvent = _defaultEvent;
desc._defaultProperty = _defaultProperty;
desc._attributes = _attributes;
desc._events = _events;
desc.OriginalProperties = OriginalProperties;
// track values
List<PropertyDescriptor> properties = new List<PropertyDescriptor>();
foreach (PropertyDescriptor pd in Properties)
{
DynamicProperty ap = new DynamicProperty(desc, pd, component);
properties.Add(ap);
}
desc.Properties = new PropertyDescriptorCollection(properties.ToArray());
return desc;
}
public object Component { get; private set; }
public string ClassName { get; set; }
public string ComponentName { get; set; }
AttributeCollection ICustomTypeDescriptor.GetAttributes()
{
return _attributes;
}
string ICustomTypeDescriptor.GetClassName()
{
if (ClassName != null)
return ClassName;
if (Component != null)
return Component.GetType().Name;
if (_type != null)
return _type.Name;
return null;
}
string ICustomTypeDescriptor.GetComponentName()
{
if (ComponentName != null)
return ComponentName;
return Component != null ? Component.ToString() : null;
}
TypeConverter ICustomTypeDescriptor.GetConverter()
{
return _typeConverter;
}
EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
{
return _defaultEvent;
}
PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
{
return _defaultProperty;
}
object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
{
object editor;
if (_editors.TryGetValue(editorBaseType, out editor))
return editor;
return null;
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
{
return _events;
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
{
return _events;
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
{
return Properties;
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
return Properties;
}
object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
{
return Component;
}
}

Autocomplete textbox highlighting the typed character in the suggestion list

I have been working on AutoCompleteTextView. I was able to get the suggestion and all in the drop down list as we type.
My question is: Can we highlight the typed character in the suggestion drop down list?
I have achieved the functionality. The solution is as follows:
AutoCompleteAdapter.java
public class AutoCompleteAdapter extends ArrayAdapter<String> implements
Filterable {
private ArrayList<String> fullList;
private ArrayList<String> mOriginalValues;
private ArrayFilter mFilter;
LayoutInflater inflater;
String text = "";
public AutoCompleteAdapter(Context context, int resource,
int textViewResourceId, List<String> objects) {
super(context, resource, textViewResourceId, objects);
fullList = (ArrayList<String>) objects;
mOriginalValues = new ArrayList<String>(fullList);
inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return fullList.size();
}
#Override
public String getItem(int position) {
return fullList.get(position);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
// tvViewResourceId = (TextView) view.findViewById(android.R.id.text1);
String item = getItem(position);
Log.d("item", "" + item);
if (convertView == null) {
convertView = view = inflater.inflate(
android.R.layout.simple_dropdown_item_1line, null);
}
// Lookup view for data population
TextView myTv = (TextView) convertView.findViewById(android.R.id.text1);
myTv.setText(highlight(text, item));
return view;
}
#Override
public Filter getFilter() {
if (mFilter == null) {
mFilter = new ArrayFilter();
}
return mFilter;
}
private class ArrayFilter extends Filter {
private Object lock;
#Override
protected FilterResults performFiltering(CharSequence prefix) {
FilterResults results = new FilterResults();
if (prefix != null) {
text = prefix.toString();
}
if (mOriginalValues == null) {
synchronized (lock) {
mOriginalValues = new ArrayList<String>(fullList);
}
}
if (prefix == null || prefix.length() == 0) {
synchronized (lock) {
ArrayList<String> list = new ArrayList<String>(
mOriginalValues);
results.values = list;
results.count = list.size();
}
} else {
final String prefixString = prefix.toString().toLowerCase();
ArrayList<String> values = mOriginalValues;
int count = values.size();
ArrayList<String> newValues = new ArrayList<String>(count);
for (int i = 0; i < count; i++) {
String item = values.get(i);
if (item.toLowerCase().contains(prefixString)) {
newValues.add(item);
}
}
results.values = newValues;
results.count = newValues.size();
}
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
if (results.values != null) {
fullList = (ArrayList<String>) results.values;
} else {
fullList = new ArrayList<String>();
}
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}
public static CharSequence highlight(String search, String originalText) {
// ignore case and accents
// the same thing should have been done for the search text
String normalizedText = Normalizer
.normalize(originalText, Normalizer.Form.NFD)
.replaceAll("\\p{InCombiningDiacriticalMarks}+", "")
.toLowerCase(Locale.ENGLISH);
int start = normalizedText.indexOf(search.toLowerCase(Locale.ENGLISH));
if (start < 0) {
// not found, nothing to to
return originalText;
} else {
// highlight each appearance in the original text
// while searching in normalized text
Spannable highlighted = new SpannableString(originalText);
while (start >= 0) {
int spanStart = Math.min(start, originalText.length());
int spanEnd = Math.min(start + search.length(),
originalText.length());
highlighted.setSpan(new ForegroundColorSpan(Color.BLUE),
spanStart, spanEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
start = normalizedText.indexOf(search, spanEnd);
}
return highlighted;
}
}
}
MainActivity.java
public class MainActivity extends Activity {
String[] languages = { "C", "C++", "Java", "C#", "PHP", "JavaScript",
"jQuery", "AJAX", "JSON" };
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
List<String> wordList = new ArrayList<String>();
Collections.addAll(wordList, languages);
AutoCompleteAdapter adapter = new AutoCompleteAdapter(this,
android.R.layout.simple_dropdown_item_1line,
android.R.id.text1,wordList);
AutoCompleteTextView acTextView = (AutoCompleteTextView) findViewById(R.id.languages);
acTextView.setThreshold(1);
acTextView.setAdapter(adapter);
}
}
Working like charm!
Enjoy!
I reckon that should be possible, provided you know the index/indices of the character(s) the user typed last. You can then use a SpannableStringBuilder and set a ForegroundColorSpan and BackgroundColorSpan to give the character(s) the appearance of a highlight.
The idea looks somewhat like this:
// start & end of the highlight
int start = ...;
int end = ...;
SpannableStringBuilder builder = new SpannableStringBuilder(suggestionText);
// set foreground color (text color) - optional, you may not want to change the text color too
builder.setSpan(new ForegroundColorSpan(Color.RED), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// set background color
builder.setSpan(new BackgroundColorSpan(Color.YELLOW), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// set result to AutoCompleteTextView
autocompleteTextview.setText(builder);
Note that the 'highlight' will remain as long as you don't type another character. You may want to remove the highlight when e.g. the user changes the cursor position in the AutoCompleteTextView, but I'll leave that up to you.
I know it's to late for answering this question , But as I personally battled to find the answer , finally I wrote it myself (with the help of the answer from #MH. ofcourse), so here it is :
First , You have to create a Custom ArrayAdapter :
public class AdapterAustocomplete extends ArrayAdapter<String> {
private static final String TAG = "AdapterAustocomplete";
String q = "";
public AdapterAustocomplete(Context context, int resource, List objects) {
super(context, resource, objects);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
String item = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView =
// I'll use a custom view for each Item , this way I can customize it also!
G.inflater.from(getContext()).inflate(R.layout.textview_autocomplete, parent, false);
}
// Lookup view for data population
TextView myTv = (TextView) convertView.findViewById(R.id.txt_autocomplete);
int start = item.indexOf(q);
int end = q.length()+start;
SpannableStringBuilder builder = new SpannableStringBuilder(item);
builder.setSpan(new ForegroundColorSpan(Color.RED), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
myTv.setText(builder);
return convertView;
}
public void setQ(String q) {
this.q = q;
}
}
And in the Code that you want to set the adapter for AutoCompleteTextView ;
AutoCompleteTextView myAutoComplete = findViewById(its_id);
AdapterAustocomplete adapter_autoComplete = new AdapterAustocomplete(getActivity(), 0, items); // items is an arrayList of Strings
adapter_autoComplete.setQ(q);
myAutoComplete.setAdapter(adapter_autoComplete);
Thanks to vadher jitendra I wrote the same and fixed some bugs.
Changed a dropdown layout to own.
Added showing a full list when clicking inside AutoCompleteTextView.
Fixed a bug of freezing the list when showing (added a check for empty string in highlight).
row_dropdown.xml (item layout):
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/text1"
style="?android:attr/dropDownItemStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:ellipsize="marquee"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:singleLine="true"
android:textColor="#333333"
android:textSize="15sp"
tools:text="text"
tools:textAppearance="?android:attr/textAppearanceLargePopupMenu" />
To filter a list when typing we should implement ArrayAdapter. It depends on items (T class). You can later use AutoCompleteAdapter<String> or any data class you like.
AutoCompleteAdapter:
import android.content.Context;
import android.graphics.Typeface;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.StyleSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class AutoCompleteAdapter<T> extends ArrayAdapter<T> implements Filterable {
private Context context;
#LayoutRes
private int layoutRes;
#IdRes
private int textViewResId;
private ArrayList<T> fullList;
private ArrayList<T> originalValues;
private ArrayFilter filter;
private LayoutInflater inflater;
private String query = "";
public AutoCompleteAdapter(#NonNull Context context, #LayoutRes int resource, #IdRes int textViewResourceId, #NonNull List<T> objects) {
super(context, resource, textViewResourceId, objects);
this.context = context;
layoutRes = resource;
textViewResId = textViewResourceId;
fullList = (ArrayList<T>) objects;
originalValues = new ArrayList<>(fullList);
inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return fullList.size();
}
#Override
public T getItem(int position) {
return fullList.get(position);
}
/**
* You can use either
* vadher jitendra method (getView)
* or get the method from ArrayAdapter.java.
*/
// #NotNull
// #Override
// public View getView(int position, View convertView, ViewGroup parent) {
// View view = convertView;
// T item = getItem(position);
// Log.d("item", "" + item);
// if (convertView == null) {
// convertView = view = inflater.inflate(layoutRes, null);
// }
// // Lookup view for data population
// TextView myTv = convertView.findViewById(textViewResId);
// myTv.setText(highlight(query, item));
// return view;
// }
#Override
public #NonNull
View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
return createViewFromResource(inflater, position, convertView, parent, layoutRes);
}
private #NonNull
View createViewFromResource(#NonNull LayoutInflater inflater, int position,
#Nullable View convertView, #NonNull ViewGroup parent, int resource) {
final View view;
final TextView text;
if (convertView == null) {
view = inflater.inflate(resource, parent, false);
} else {
view = convertView;
}
try {
if (textViewResId == 0) {
// If no custom field is assigned, assume the whole resource is a TextView
text = (TextView) view;
} else {
// Otherwise, find the TextView field within the layout
text = view.findViewById(textViewResId);
if (text == null) {
throw new RuntimeException("Failed to find view with ID "
+ context.getResources().getResourceName(textViewResId)
+ " in item layout");
}
}
} catch (ClassCastException e) {
Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
throw new IllegalStateException(
"ArrayAdapter requires the resource ID to be a TextView", e);
}
final T item = getItem(position);
text.setText(highlight(query, item.toString()));
// if (item instanceof CharSequence) {
// text.setText(highlight(query, (CharSequence) item));
// } else {
// text.setText(item.toString());
// }
return view;
}
#Override
public #NonNull
Filter getFilter() {
if (filter == null) {
filter = new ArrayFilter();
}
return filter;
}
private class ArrayFilter extends Filter {
private final Object lock = new Object();
#Override
protected FilterResults performFiltering(CharSequence prefix) {
FilterResults results = new FilterResults();
if (prefix == null) {
query = "";
} else {
query = prefix.toString();
}
if (originalValues == null) {
synchronized (lock) {
originalValues = new ArrayList<>(fullList);
}
}
if (prefix == null || prefix.length() == 0) {
synchronized (lock) {
ArrayList<T> list = new ArrayList<>(originalValues);
results.values = list;
results.count = list.size();
}
} else {
final String prefixString = prefix.toString().toLowerCase();
ArrayList<T> values = originalValues;
int count = values.size();
ArrayList<T> newValues = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
T item = values.get(i);
if (item.toString().toLowerCase().contains(prefixString)) {
newValues.add(item);
}
}
results.values = newValues;
results.count = newValues.size();
}
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results.values != null) {
fullList = (ArrayList<T>) results.values;
} else {
fullList = new ArrayList<>();
}
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}
private static CharSequence highlight(#NonNull String search, #NonNull CharSequence originalText) {
if (search.isEmpty())
return originalText;
// ignore case and accents
// the same thing should have been done for the search text
String normalizedText = Normalizer
.normalize(originalText, Normalizer.Form.NFD)
.replaceAll("\\p{InCombiningDiacriticalMarks}+", "")
.toLowerCase(Locale.ENGLISH);
int start = normalizedText.indexOf(search.toLowerCase(Locale.ENGLISH));
if (start < 0) {
// not found, nothing to do
return originalText;
} else {
// highlight each appearance in the original text
// while searching in normalized text
Spannable highlighted = new SpannableString(originalText);
while (start >= 0) {
int spanStart = Math.min(start, originalText.length());
int spanEnd = Math.min(start + search.length(),
originalText.length());
highlighted.setSpan(new StyleSpan(Typeface.BOLD), spanStart, spanEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
start = normalizedText.indexOf(search, spanEnd);
}
return highlighted;
}
}
}
In order to show dropdown list when clicked inside AutoCompleteTextView we need to override setOnTouchListener as described in https://stackoverflow.com/a/26036902/2914140. Lint also prints warnings, so we have to write a custom view:
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import androidx.appcompat.widget.AppCompatAutoCompleteTextView;
/*
Avoids a warning "Custom view `AutoCompleteTextView` has setOnTouchListener called on it but does not override performClick".
*/
public class AutoCompleteTV extends AppCompatAutoCompleteTextView {
public AutoCompleteTV(Context context) {
super(context);
}
public AutoCompleteTV(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AutoCompleteTV(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
performClick();
}
return super.onTouchEvent(event);
}
#Override
public boolean performClick() {
super.performClick();
return true;
}
}
Then use it in activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.textfield.TextInputLayout
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.example.autocompletetextview1.AutoCompleteTV
android:id="#+id/languages"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:completionThreshold="1"
android:hint="language"
android:imeOptions="actionNext"
android:maxLines="1"
android:paddingLeft="10dp"
android:paddingTop="15dp"
android:paddingRight="10dp"
android:paddingBottom="15dp"
android:singleLine="true"
android:textColor="#333333"
android:textColorHint="#808080"
android:textSize="12sp" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
I use TextInputLayout here for better decoration, in this case we have to add Material Design Components:
in build.gradle:
implementation 'com.google.android.material:material:1.3.0-alpha01'
and in styles.xml:
<style name="AppTheme" parent="Theme.MaterialComponents.Light.DarkActionBar">
...
MainActivity:
import android.os.Bundle;
import android.view.MotionEvent;
import android.widget.AutoCompleteTextView;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
String[] items = {"C", "C++", "Java", "C#", "PHP", "JavaScript", "jQuery", "AJAX", "JSON"};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<DataClass> wordList = new ArrayList<>();
for (int i = 0; i < items.length; i++) {
DataClass data = new DataClass(i, items[i]);
wordList.add(data);
}
AutoCompleteAdapter<DataClass> adapter = new AutoCompleteAdapter<>(this,
R.layout.row_dropdown, R.id.text1, wordList);
//adapter.setDropDownViewResource(R.layout.row_dropdown);
AutoCompleteTV acTextView = findViewById(R.id.languages);
acTextView.setThreshold(1);
acTextView.setAdapter(adapter);
acTextView.setText("Java");
acTextView.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
((AutoCompleteTextView) v).showDropDown();
v.requestFocus();
v.performClick(); // Added to avoid warning "onTouch lambda should call View#performClick when a click is detected".
}
return false;
}
);
}
}

CheckboxCell, MultiSelectionModel unwantonly reset DataGrid's data

Using GWT 2.4...
I am building upon a complex Composite dual view/edit mode implementation that is backed GWT's DataGrid and MultiSelectionModel. My goal is for a user to be able to click a checkbox in each row that they'd like to post updates for.
Here's a screenshot from a semi-functional interface:
Note the selected (highlighted) rows.
Now the problem is that when I type something in any of the cells (e.g., the first row's $ cell under the $/Mw 1 composite cell header), then click that row's checkbox (or any other row's checkbox for that matter) to select or de-select, the value gets reset to the original value when the screen's data was first requested. Not desired behavior by any stretch!
Let's take a look at my custom implementation for the grid. (Excuse the length).
public abstract class ToggleableGrid<T extends Identifiable<?>> extends Composite {
private static final int CHKBOX_COLUMN_WIDTH = App.INSTANCE.checkboxColumnWidth();
private static final DisplayMode DEFAULT_MODE = DisplayMode.VIEW;
private ProvidesKey<T> keyProvider;
private DataGrid<T> grid;
private MultiSelectionModel<T> selectionModel;
private ListDataProvider<T> dataProvider;
private int tabIndex = 0;
public ToggleableGrid() {
final DataGridConfiguration config = new DefaultDataGridConfiguration();
initGrid(config);
}
public ToggleableGrid(DataGridConfiguration config) {
initGrid(config);
}
private void initGrid(DataGridConfiguration config) {
keyProvider = new ProvidesKey<T>() {
#Override
public Object getKey(T item) {
return item == null ? null : item.getId();
}
};
grid = new DataGrid<T>(config.getPageSize(), config.getResources(), keyProvider);
// Set the message to display when the table is empty.
grid.setEmptyTableWidget(new Label(UiMessages.INSTANCE.no_results()));
initWidget(grid);
setVisible(true);
}
public void setInput(List<T> content) {
setInput(content, DEFAULT_MODE);
}
public void setInput(List<T> content, DisplayMode mode) {
resetTableColumns();
if (isInEditMode(mode)) {
// Add a selection model so we can select cells
selectionModel = new MultiSelectionModel<T>(keyProvider);
grid.setSelectionModel(selectionModel, DefaultSelectionEventManager.<T> createCheckboxManager(0));
addRowSelector();
}
dataProvider = new ListDataProvider<T>(content);
final ListHandler<T> sortHandler = new ListHandler<T>(dataProvider.getList());
grid.addColumnSortHandler(sortHandler);
initializeStructure(constructMetadata(), sortHandler, mode);
dataProvider.addDataDisplay(grid);
}
// see https://stackoverflow.com/questions/3772480/remove-all-columns-from-a-celltable
// concrete classes are forced to maintain a handle on all columns added
private void resetTableColumns() {
for (final Column<T, ?> column: allColumns()) {
grid.removeColumn(column);
}
allColumns().clear();
}
protected boolean isInEditMode(DisplayMode currentDisplayMode) {
boolean result = false;
if (currentDisplayMode.equals(DisplayMode.EDIT)) {
result = true;
}
return result;
}
protected abstract Set<Column<T, ?>> allColumns();
protected abstract TableMetadata constructMetadata();
protected abstract void initializeStructure(TableMetadata metadata, ListHandler<T> sortHandler, DisplayMode mode);
protected void setColumnHorizontalAlignment(Column<T, ?> column, HorizontalAlignmentConstant alignment) {
column.setHorizontalAlignment(alignment);
}
// TODO figure out how to add a checkbox to column header that provides select/de-select all capability
// see https://stackoverflow.com/questions/6174689/gwt-celltable-programmatically-select-checkboxcell
protected void addRowSelector() {
final Column<T, Boolean> rowSelectColumn = new Column<T, Boolean>(new CheckboxCell(true, false)) {
#Override
public Boolean getValue(T value) {
Boolean result;
// check for null value and return null;
if(value == null || value.getId() == null) {
result = null;
} else { // get value from the selection model
result = selectionModel.isSelected(value);
}
return result;
}
};
addColumn(rowSelectColumn, UiMessages.INSTANCE.select());
setColumnWidth(rowSelectColumn, CHKBOX_COLUMN_WIDTH, Unit.PX);
setColumnHorizontalAlignment(rowSelectColumn, HasHorizontalAlignment.ALIGN_CENTER);
}
protected void setColumnWidth(Column<T, ?> column, int width, Unit unit) {
grid.setColumnWidth(column, width, unit);
}
protected void addColumn(Column<T, ?> column, String columnHeaderName) {
addColumn(column, columnHeaderName, HasHorizontalAlignment.ALIGN_RIGHT);
}
protected void addColumn(Column<T, ?> column, String columnHeaderName, HorizontalAlignmentConstant alignment) {
final SafeHtmlBuilder sb = new SafeHtmlBuilder();
final String divStart = "<div align=\""+ alignment.getTextAlignString() + "\" class=\"" +UiResources.INSTANCE.style().word_wrap() + "\">";
sb.appendHtmlConstant(divStart).appendEscaped(columnHeaderName).appendHtmlConstant("</div>");
final SafeHtml header = sb.toSafeHtml();
grid.addColumn(column, header);
allColumns().add(column);
}
protected CompositeCell<T> generateCompositeCell(final List<HasCell<T, ?>> hasCells) {
final CompositeCell<T> compositeCell = new CompositeCell<T>(hasCells) {
#Override
public void render(Context context, T value, SafeHtmlBuilder sb) {
sb.appendHtmlConstant("<table><tbody><tr>");
super.render(context, value, sb);
sb.appendHtmlConstant("</tr></tbody></table>");
}
#Override
protected Element getContainerElement(Element parent) {
// Return the first TR element in the table.
return parent.getFirstChildElement().getFirstChildElement().getFirstChildElement();
}
#Override
protected <X> void render(Context context, T value,
SafeHtmlBuilder sb, HasCell<T, X> hasCell) {
final Cell<X> cell = hasCell.getCell();
sb.appendHtmlConstant("<td>");
cell.render(context, hasCell.getValue(value), sb);
sb.appendHtmlConstant("</td>");
}
};
return compositeCell;
}
// FIXME not working quite the way we'd expect, index incremented within column for each row, not each row by column
protected int nextTabIndex() {
tabIndex++;
return tabIndex;
}
protected AbstractCellTable<T> getGrid() {
return grid;
}
/**
* Gets the selected (row(s) of) data from grid (used in edit mode)
* #return the selected data (as per selection model)
*/
public List<T> getSelectedData() {
final List<T> data = new ArrayList<T>();
data.addAll(selectionModel.getSelectedSet());
return data;
}
/**
* Gets all (row(s) of) data in grid (used in edit mode)
* #return all data as list
*/
public List<T> getAllData() {
return dataProvider.getList();
}
/**
* Clears the currently selected (row(s) of) data (used in edit mode)
*/
public void clearSelectedData() {
selectionModel.clear();
grid.redraw();
}
}
So, the interesting methods to stare at above (I think) are setInput, generateCompositeCell and addRowSelector.
We initialize the grid with List data and set a display mode in setInput. It's here as well that the selection model is initialized. It uses GWT's DefaultSelectionEventManager createCheckboxManager().
I've been trying to grok the event model, but it eludes me. I've visited the following sources online, but have come up short on avenues to solving this problem.
-- https://groups.google.com/forum/?fromgroups#!topic/google-web-toolkit/k5sfURxDaVg
AbstractInputCell's getConsumedEventsImpl adds focus, blur and keydown, so this (I believe) is not a track I need to explore
-- GWT CellTable programmatically select CheckBoxCell
The various ways you can instantiate a CheckBoxCell got me curious, and I've tried many constructor argument permutations, but the one I settled on (true, false) is (I believe) the right one
Agreeing here and now (before being reprimanded) that there's perhaps some unnecessary complexity in my implementation, but I am looking for guidance nonetheless. Thanks!
Update
If it helps here's an impl of the aforementioned ToggleableGrid. If anything it gives you more detail on what goes into each CompositeCell. For details on AbstractValidatableColumn and ValidatableInputCell, see: In search of a GWT validation example... where art thou?.
public class EnergyOfferGrid extends ToggleableGrid<EnergyOfferDTO> {
public EnergyOfferGrid() {
super();
}
public EnergyOfferGrid(DataGridConfiguration config) {
super(config);
}
private static final int MAX_NUMBER_OF_MW_PRICE_POINTS = App.INSTANCE.maxNoOfMwPricePoints();
private Set<Column<EnergyOfferDTO, ?>> columns = new HashSet<Column<EnergyOfferDTO, ?>>();
#Override
protected Set<Column<EnergyOfferDTO, ?>> allColumns() {
return columns;
}
#Override
protected TableMetadata constructMetadata() {
final TableMetadata metadata = new TableMetadata();
// TODO Consider a predefined set of ReferenceData to be held in a common package
// Use Slope
metadata.addColumnMetadata(UiMessages.INSTANCE.use_slope(), new String[] {UiMessages.INSTANCE.yes(), UiMessages.INSTANCE.no()}, new String[] {"true", "false"});
return metadata;
}
#Override
protected void initializeStructure(TableMetadata metadata, ListHandler<EnergyOfferDTO> sortHandler, DisplayMode currentDisplayMode) {
addHourColumn(sortHandler);
addUseSlopeColumn(metadata, sortHandler, currentDisplayMode);
for (int i = 0; i < MAX_NUMBER_OF_MW_PRICE_POINTS; i++) { // zero-based indexing
addPriceMwColumn(i, currentDisplayMode);
}
}
protected void addHourColumn(ListHandler<EnergyOfferDTO> sortHandler) {
final Column<EnergyOfferDTO, String> hourColumn = new Column<EnergyOfferDTO, String>(new TextCell()) {
#Override
public String getValue(EnergyOfferDTO energyOffer) {
String result = "";
if (energyOffer.getId() != null) {
final String isoDateTime = energyOffer.getId().getOperatingHour();
if (isoDateTime != null && !isoDateTime.isEmpty()) {
final Date dateTime = CSTimeUtil.isoToDate(isoDateTime);
if (dateTime != null) {
result = CSTimeUtil.dateToHour(dateTime);
}
}
}
return result;
}
};
hourColumn.setSortable(true);
sortHandler.setComparator(hourColumn, new Comparator<EnergyOfferDTO>() {
#Override
public int compare(EnergyOfferDTO eo1, EnergyOfferDTO eo2) {
final String date1 = eo1.getId() != null ? eo1.getId().getOperatingHour() : "";
final String date2 = eo2.getId() != null ? eo2.getId().getOperatingHour() : "";
return date1.compareTo(date2);
}
});
// We know that the data is sorted by hour by default.
getGrid(). getColumnSortList().push(hourColumn);
addColumn(hourColumn, UiMessages.INSTANCE.hour());
setColumnWidth(hourColumn, 45, Unit.PX);
setColumnHorizontalAlignment(hourColumn, HasHorizontalAlignment.ALIGN_RIGHT);
}
protected void addUseSlopeColumn(TableMetadata metadata, ListHandler<EnergyOfferDTO> sortHandler, DisplayMode currentDisplayMode) {
final ReferenceData refData = metadata.allColumnMetadata().get(UiMessages.INSTANCE.use_slope());
Column<EnergyOfferDTO, String> useSlopeColumn;
Cell<String> cell;
if (isInEditMode(currentDisplayMode)) {
cell = new ReferenceDataBackedSelectionCell(refData);
} else {
cell = new TextCell();
}
useSlopeColumn = new Column<EnergyOfferDTO, String>(cell) {
#Override
public String getValue(EnergyOfferDTO energyOffer) {
return refData.getDisplayValueForSubmitValue(Boolean.toString(energyOffer.isSlopeUsed()));
}
};
useSlopeColumn.setSortable(true);
sortHandler.setComparator(useSlopeColumn, new Comparator<EnergyOfferDTO>() {
#Override
public int compare(EnergyOfferDTO eo1, EnergyOfferDTO eo2) {
final String slopeUsed1 = String.valueOf(eo1.isSlopeUsed());
final String slopeUsed2 = String.valueOf(eo1.isSlopeUsed());
return slopeUsed1.compareTo(slopeUsed2);
}
});
addColumn(useSlopeColumn, UiMessages.INSTANCE.use_slope());
setColumnWidth(useSlopeColumn, 75, Unit.PX);
setColumnHorizontalAlignment(useSlopeColumn, HasHorizontalAlignment.ALIGN_RIGHT);
}
protected void addPriceMwColumn(final int colIndex, DisplayMode currentDisplayMode) {
// Construct a composite cell for energy offers that includes a pair of text inputs
final List<HasCell<EnergyOfferDTO, ?>> columns = new ArrayList<
HasCell<EnergyOfferDTO, ?>>();
// this DTO is passed along so that price and mw values for new entries are kept together
final OfferPriceMwPair newOfferPriceMwPair = new OfferPriceMwPair();
// Price
final Column<EnergyOfferDTO, String> priceColumn = generatePriceColumn(colIndex, newOfferPriceMwPair, currentDisplayMode);
columns.add(priceColumn);
// MW
final Column<EnergyOfferDTO, String> mwColumn = generateMwColumn(colIndex, newOfferPriceMwPair, currentDisplayMode);
columns.add(mwColumn);
// Composite
final CompositeCell<EnergyOfferDTO> priceMwColumnInnards = generateCompositeCell(columns);
final IdentityColumn<EnergyOfferDTO> priceMwColumn = new IdentityColumn<EnergyOfferDTO>(priceMwColumnInnards);
final StringBuilder colHeader = new StringBuilder();
colHeader.append(UiMessages.INSTANCE.price_mw_header()).append(" ").append(String.valueOf(colIndex + 1));
addColumn(priceMwColumn, colHeader.toString());
setColumnWidth(priceMwColumn, 7, Unit.EM);
setColumnHorizontalAlignment(priceMwColumn, HasHorizontalAlignment.ALIGN_RIGHT);
}
protected Column<EnergyOfferDTO, String> generatePriceColumn(final int colIndex, final OfferPriceMwPair newOfferPriceMwPair, DisplayMode currentDisplayMode) {
Column<EnergyOfferDTO, String> priceColumn;
if (isInEditMode(currentDisplayMode)) {
priceColumn = new BigDecimalValidatableColumn<EnergyOfferDTO, OfferPriceMwPair>(nextTabIndex(), getGrid()) {
#Override
public String getValue(EnergyOfferDTO energyOffer) {
return obtainPriceValue(colIndex, energyOffer, false);
}
#Override
public void doUpdate(int index, EnergyOfferDTO energyOffer, String value) {
if (value != null && !value.isEmpty()) {
// number format exceptions should be caught and handled by event bus's handle method
final double valueAsDouble = NumberFormat.getDecimalFormat().parse(value);
final BigDecimal price = BigDecimal.valueOf(valueAsDouble);
final List<OfferPriceMwPair> offerPriceCurve = energyOffer.getCurve();
final OfferPriceMwPair offerPriceMwPair = offerPriceCurve.get(colIndex);
if (offerPriceMwPair == null) { // we have a new price value
newOfferPriceMwPair.setPrice(price);
offerPriceCurve.add(newOfferPriceMwPair);
} else {
offerPriceMwPair.setPrice(price);
}
}
}
#Override
protected String getPropertyName() {
return "price";
}
#Override
protected Class<OfferPriceMwPair> getPropertyOwner() {
return OfferPriceMwPair.class;
}
};
} else {
priceColumn = new Column<EnergyOfferDTO, String>(new TextCell()) {
#Override
public String getValue(EnergyOfferDTO energyOffer) {
final String result = obtainPriceValue(colIndex, energyOffer, true);
return result;
}
};
}
return priceColumn;
}
private String obtainPriceValue(final int colIndex, EnergyOfferDTO energyOffer, boolean withCurrency) {
String result = "";
if (energyOffer != null) {
final List<OfferPriceMwPair> offerPriceCurve = energyOffer.getCurve();
final int numberOfPairs = offerPriceCurve.size();
if (colIndex < numberOfPairs) {
final OfferPriceMwPair offerPriceMwPair = offerPriceCurve.get(colIndex);
if (offerPriceMwPair != null) {
final BigDecimal price = offerPriceMwPair.getPrice();
if (price != null) {
final double value = price.doubleValue();
if (withCurrency) {
result = NumberFormat.getCurrencyFormat().format(value);
} else {
result = NumberFormat.getDecimalFormat().format(value);
}
}
}
}
}
return result;
}
protected Column<EnergyOfferDTO, String> generateMwColumn(final int colIndex, final OfferPriceMwPair newOfferPriceMwPair, DisplayMode currentDisplayMode) {
Column<EnergyOfferDTO, String> mwColumn;
if (isInEditMode(currentDisplayMode)) {
mwColumn = new BigDecimalValidatableColumn<EnergyOfferDTO, PriceMwPair>(nextTabIndex(), getGrid()) {
#Override
public String getValue(EnergyOfferDTO energyOffer) {
return obtainMwValue(colIndex, energyOffer);
}
#Override
public void doUpdate(int index, EnergyOfferDTO energyOffer, String value) {
if (value != null && !value.isEmpty()) {
// number format exceptions should be caught and handled by event bus's handle method
final double valueAsDouble = NumberFormat.getDecimalFormat().parse(value);
final BigDecimal mw = BigDecimal.valueOf(valueAsDouble);
final List<OfferPriceMwPair> offerPriceCurve = energyOffer.getCurve();
final OfferPriceMwPair offerPriceMwPair = offerPriceCurve.get(colIndex);
if (offerPriceMwPair == null) { // we have a new price value
newOfferPriceMwPair.setMw(mw);
offerPriceCurve.add(newOfferPriceMwPair);
} else {
offerPriceMwPair.setMw(mw);
}
}
}
#Override
protected String getPropertyName() {
return "mw";
}
#Override
protected Class<PriceMwPair> getPropertyOwner() {
return PriceMwPair.class;
}
};
} else {
mwColumn = new Column<EnergyOfferDTO, String>(new TextCell()) {
#Override
public String getValue(EnergyOfferDTO energyOffer) {
final String result = obtainMwValue(colIndex, energyOffer);
return result;
}
};
}
return mwColumn;
}
private String obtainMwValue(final int colIndex, EnergyOfferDTO energyOffer) {
String result = "";
if (energyOffer != null) {
final List<OfferPriceMwPair> offerPriceCurve = energyOffer.getCurve();
final int numberOfPairs = offerPriceCurve.size();
if (colIndex < numberOfPairs) {
final PriceMwPair offerPriceMwPair = offerPriceCurve.get(colIndex);
if (offerPriceMwPair != null) {
final BigDecimal mw = offerPriceMwPair.getMw();
if (mw != null) {
result = NumberFormat.getDecimalFormat().format(mw);
}
}
}
}
return result;
}
}
All that custom work w.r.t. WrapperCell and CompositeValidatableColumn was unnecessary.
It turns out that there's a way you should not construct CompositeCells. See http://code.google.com/p/google-web-toolkit/issues/detail?id=5714. My CompositeCells were not receiving events. So, I changed the way I construct them in ToggleableGrid.
protected CompositeCell<T> generateCompositeCell(final List<HasCell<T, String>> hasCells) {
final CompositeCell<T> compositeCell = new CompositeCell<T>(hasCells) {
// to not run afoul of http://code.google.com/p/google-web-toolkit/issues/detail?id=5714
#Override
public void render(Context context, T value, SafeHtmlBuilder sb) {
sb.appendHtmlConstant("<div style=\"display: inline\">");
super.render(context, value, sb);
sb.appendHtmlConstant("</div>");
}
#Override
protected Element getContainerElement(Element parent) {
// Return the first element in the DIV.
return parent.getFirstChildElement();
}
};
return compositeCell;
}
After that change and incorporating my other validation-oriented classes: ValidatableFieldUpdater, AbstractValidatableColumn (and derivatives), ValidatableInputField and ConversionResult, life couldn't be more grand!

Disable ButtonCell in a celltable

In my CellTable, One column has ButtonCells. So I need to disable theses ButtonCells by clicking on a button which is located outside the CellTable.
You could create your own Button Cell class. For example:
import com.google.gwt.cell.client.AbstractSafeHtmlCell;
import com.google.gwt.cell.client.Cell;
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.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.text.shared.SafeHtmlRenderer;
import com.google.gwt.text.shared.SimpleSafeHtmlRenderer;
/**
* A {#link Cell} used to render a button.
*/
public class StyledButtonCell extends AbstractSafeHtmlCell<String> {
private String disabledString = "";
private boolean disabled = false;
/**
* Construct a new ButtonCell that will use a {#link SimpleSafeHtmlRenderer}.
*/
public StyledButtonCell() {
this(SimpleSafeHtmlRenderer.getInstance());
}
/**
* Construct a new ButtonCell that will use a given {#link SafeHtmlRenderer}.
*
* #param renderer a {#link SafeHtmlRenderer SafeHtmlRenderer<String>} instance
*/
public StyledButtonCell(SafeHtmlRenderer<String> renderer) {
super(renderer, "click", "keydown");
}
#Override
public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
super.onBrowserEvent(context, parent, value, event, valueUpdater);
if ("click".equals(event.getType())) {
EventTarget eventTarget = event.getEventTarget();
if (!Element.is(eventTarget)) {
return;
}
if (parent.getFirstChildElement().isOrHasChild(Element.as(eventTarget))) {
// Ignore clicks that occur outside of the main element.
onEnterKeyDown(context, parent, value, event, valueUpdater);
}
}
}
#Override
public void render(Context context, SafeHtml data, SafeHtmlBuilder sb) {
sb.appendHtmlConstant("<button type=\"button\" tabindex=\"-1\"" + disabledString + ">");
if (data != null) {
sb.append(data);
}
sb.appendHtmlConstant("</button>");
}
#Override
protected void onEnterKeyDown(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
if (valueUpdater != null) {
valueUpdater.update(value);
}
}
public boolean isDisabled() {
return disabled;
}
public void setDisabled(boolean disabled) {
this.disabled = disabled;
if (disabled) {
disabledString = "disabled=\"disabled\"";
} else {
disabledString = "";
}
}
}
Then use this with your cell table:
final StyledButtonCell buttonCell = new StyledButtonCell();
buttonColumn = new Column<SomeItem, String>(buttonCell) {
public String getValue(SomeItem object) {
// The value to display in the button.
return "Go";
}
};
To disable the button, simply call:
buttonCell.setDisabled(true);
table.redraw();
If you don't need to "rename" your button, you can also create your own based on Boolean abstract cell:
public class CustomButtonCell extends AbstractEditableCell<Boolean, Boolean> {
private static final SafeHtml ENABLED = SafeHtmlUtils.fromSafeConstant("<button type=\"button\" tabindex=\"-1\">");
private static final SafeHtml DISABLED = SafeHtmlUtils.fromSafeConstant("<button type=\"button\" tabindex=\"-1\" disabled=\"disabled\">");
private static final SafeHtml CLOSE_BRACKET = SafeHtmlUtils.fromSafeConstant("</button>");
private final boolean dependsOnSelection;
private final boolean handlesSelection;
private final String text;
public CustomButtonCell(final String text) {
this(false, false, text);
}
public CustomButtonCell(boolean dependsOnSelection, boolean handlesSelection, String text) {
super(BrowserEvents.CHANGE, BrowserEvents.CLICK, BrowserEvents.KEYDOWN);
this.dependsOnSelection = dependsOnSelection;
this.handlesSelection = handlesSelection;
this.text = text;
}
#Override
public boolean dependsOnSelection() {
return dependsOnSelection;
}
#Override
public boolean handlesSelection() {
return handlesSelection;
}
#Override
public boolean isEditing(Context context, Element parent, Boolean value) {
return false;
}
/**
* Based on CheckboxCell
*/
#Override
public void onBrowserEvent(Context context, Element parent, Boolean value,
NativeEvent event, ValueUpdater<Boolean> valueUpdater) {
String type = event.getType();
boolean enterPressed = BrowserEvents.KEYDOWN.equals(type)
&& event.getKeyCode() == KeyCodes.KEY_ENTER;
if (BrowserEvents.CHANGE.equals(type) || BrowserEvents.CLICK.equals(type) || enterPressed) {
InputElement input = parent.getFirstChild().cast();
Boolean isChecked = input.isChecked();
if (enterPressed && (handlesSelection() || !dependsOnSelection())) {
isChecked = !isChecked;
input.setChecked(isChecked);
}
if (value != isChecked && !dependsOnSelection()) {
setViewData(context.getKey(), isChecked);
} else {
clearViewData(context.getKey());
}
if (valueUpdater != null) {
valueUpdater.update(isChecked);
}
}
}
#Override
public void render(Context context, Boolean value, SafeHtmlBuilder sb) {
// Get the view data.
Object key = context.getKey();
Boolean viewData = getViewData(key);
if (viewData != null && viewData.equals(value)) {
clearViewData(key);
viewData = null;
}
if (value != null && ((viewData != null) ? viewData : value)) {
sb.append(ENABLED);
} else {
sb.append(DISABLED);
}
sb.append(SafeHtmlUtils.fromString(text));
sb.append(CLOSE_BRACKET);
}
}
and edit it by its "get value" mechanisme
Column<TestJSO, Boolean> revokeColumn = CellTableUtils.createColumn(new CustomButtonCell("Test"),
new GetValue<TestJSO, Boolean>() {
#Override
public Boolean getValue(TestJSO value) {
return value.isEnabled();
}
});
Good morning,
that was a nice little example to do early in the morning. Here you have my solution, I'm not saying, its the best but its working!
public class _57_DisableAllButtons implements EntryPoint {
boolean enable = false;
#Override
public void onModuleLoad() {
Button b1 = new Button("Button1");
Button b2 = new Button("Button2");
Button b3 = new Button("Button3");
RootPanel.get("nameFieldContainer").add(b1);
RootPanel.get("nameFieldContainer").add(b2);
RootPanel.get("nameFieldContainer").add(b3);
Button disableAll = new Button("Disabale all");
RootPanel.get("sendButtonContainer").add(disableAll);
disableAll.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
final RootPanel rootpannel = RootPanel.get("nameFieldContainer");
int widgetcount = rootpannel.getWidgetCount();
for (int i = 0; i < widgetcount; i++) {
Widget w = rootpannel.getWidget(i);
if(w instanceof Button){
((Button) w).setEnabled(enable);
}
}
enable = !enable;
}
});
}
}