PDA

View Full Version : Ext-GWT B3 refactor



Kutu
22 May 2008, 9:54 AM
I downloaded Ext-GWT B3 yesterday and I noticed a lot of refactoring going on.

I have several questions regarding the refactoring:

1) Why?
2) WHy?
3) WHY?

I understand that Ext-GWT is still in Beta. But some of the refactoring are confusing. For example:

1) Tree can be either Single or Multi (this point applies to classes that use SelectionModel as well)

Does this require a separate class/interface to handle each selection? Can we just use a flip-flop or enum?

2) Some of the Widgets now have this inner class (or something) that represent the "Message"

Do we need this? Can a class look flat instead of consisting/returning an inner-class?

Seems like with the introduction of Generics to GWT, with each release of Ext-GWT, there's always some refactoring to use Generics or additional helper classes. I'm not sure if this is a good thing or bad.

gslender
22 May 2008, 2:21 PM
The value of generics and its use is heavily debated in Java circles... the general view is that they add value in many places.

darrellmeyer
22 May 2008, 7:31 PM
Seems like with the introduction of Generics to GWT, with each release of Ext-GWT, there's always some refactoring to use Generics or additional helper classes. I'm not sure if this is a good thing or bad. There have been quite a few API changes up to beta 3 and we recognize it can be frustrating. We felt that it was important to get things right before 1.0 is released so that the API would support future growth without the need for changes later down the line. All the major updates are now complete and there should not be any significant changes to the API going forward.

Kutu
23 May 2008, 10:35 AM
I find it confusing instead of frustrating to be honest.

Another example is the "Store" class (and perhaps ListStore). To populate a ComboBox, I have to create a model class. Why is that necessary? Can't you provide another way to populate a ComboBox with say.... a simple String class?

Grandiosa
30 May 2008, 12:35 AM
I wrote a simple generic combobox and a simple callback interface for this purpose. You don't need to deal with either Store or Model objects to use it. Feel free to use them if you like. (requires latest Beta3 build)

Use it like this:



FormPanel form = new FormPanel();
form.setFieldWidth(210);
form.setWidth(410);

final List<String> names = new ArrayList<String>();
names.add("Sarah");
names.add("Angelina");

final SimpleComboBox<String> combo1 = new SimpleComboBox<String>("Select actor");
combo1.add(names); // add list of items
combo1.add("Julia"); // add single item

combo1.addListener(new ComboBoxListener<String>() {
public void onSelectionChanged(String selected) {
Info.display("Selection", "selected item: {0}", selected);
}
});
combo1.setWidth(210);
combo1.addToForm(form);



You can use any object class as the type parameter, the SimpleComboBox uses the toString() to render the ComboBox displayfield.

Here is the code:



import com.extjs.gxt.ui.client.data.BaseModelData;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.extjs.gxt.ui.client.widget.form.FormPanel;

import java.util.List;

/**
* Simple replacement for ExtGWT's {@link com.extjs.gxt.ui.client.widget.form.ComboBox ComboBox}.
* Usage does not depend on a ExtGWT {@link com.extjs.gxt.ui.client.store.Store Store} as the
* Store is contained within this class.
* Example usage:<br>
* <pre>
*
* final List&lt;String&gt; names = new ArrayList&lt;String&gt;();
* names.add("Sarah");
* names.add("Angelina");
*
* final ListComboBox&lt;String&gt; combo1 = new ListComboBox&lt;String&gt;("Select employee");
* combo1.add(names); // adding a list
* combo1.add("Julia"); // adding a single item
*
* combo1.addListener(new ComboBoxListener&lt;String&gt;() {
* public void onSelectionChanged(String selected) {
* Info.display("Selection", "selected item: {0}", selected);
* }
* });
* combo1.setWidth(210);
* combo1.addToForm(form);
*
* </pre>
*
*/
public class SimpleComboBox<T> {

ComboBox<StoreItem> combo ;
ListStore<StoreItem> store = new ListStore<StoreItem>();

private static final String VALUE_FIELD_NAME = "value";
private static final String DISPLAY_FIELD_NAME = "display";

private class StoreItem extends BaseModelData {

private StoreItem() { }

public StoreItem(T item) {
this();
set(VALUE_FIELD_NAME, item);
set(DISPLAY_FIELD_NAME, item.toString());
}

public T getValue() { return (T)get(VALUE_FIELD_NAME); }

public String getDisplayField() { return (String)get(DISPLAY_FIELD_NAME); }

public int hashCode() {
return getValue().hashCode();
}

public boolean equals(Object obj) {
if (obj == null)
return false;
StoreItem i = (StoreItem) obj;
T item1 = i.getValue();
T item2 = this.getValue();
return item1.equals(item2);
}
}

public SimpleComboBox(String fieldLabel) {
combo = new ComboBox<StoreItem>();
combo.setFieldLabel(fieldLabel);
combo.setValueField(VALUE_FIELD_NAME);
combo.setDisplayField(DISPLAY_FIELD_NAME);
combo.setStore(store);
}

public void addToForm(FormPanel form) {
form.add(combo);
}

public void addToForm(FormPanel form, Object layoutData) {
form.add(combo, layoutData);
}

public int getSelectionIndex() {
return store.indexOf(combo.getValue());
}

public T getValue() {
StoreItem storeItem = combo.getValue();
return storeItem.getValue();
}

public void add(List<T> elements) {
for (T element : elements) {
store.add(new StoreItem(element));
}
}

public void add(T element) {
store.add(new StoreItem(element));
}

public void addListener(final ComboBoxListener<T> listener) {
combo.addSelectionChangedListener(new SelectionChangedListener<StoreItem>() {
public void selectionChanged(SelectionChangedEvent<StoreItem> sce) {
if (sce.getSelectedItem() != null) {
T item = sce.getSelectedItem().getValue();
listener.onSelectionChanged(item);
}
}
});
}

public void remove(T item) {
store.remove(new StoreItem(item));
}

public void remove(int index) {
if (index >= 0 && index < store.getCount())
store.remove(store.getAt(index));
}

public void removeAll() {
store.removeAll();
}

public void setWidth(int width) {
combo.setWidth(width);
}

public void setWidth(String width) {
combo.setWidth(width);
}

public void setEditable(boolean value) {
combo.setEditable(value);
}

public void reset() {
combo.reset();
}

public ComboBox getGxtComboBox() {
return combo;
}
}

And the interface:




/**
* Callback interface used by {@link SimpleComboBox}<br>
* SimpleComboBox uses this to simply return your selected value
* instead of the standard SelectionChangedEvent that returns a GXT Model object.
*
*/
public interface ComboBoxListener<T> {

public void onSelectionChanged(T selected);

}

gslender
30 May 2008, 2:43 AM
darrell - worth adding this convienence class plus anything else as I'm sure some folk would appreciate simple use objects for tree/table/combobox etc...

zaccret
30 May 2008, 3:28 AM
+1 for convenience classes or methods (maybe Grandiosa's class but I wonder if subclassing Component - directly or indirectly - would not be better)

I think the Store API design is great but, for simple cases (string values), convenience methods would be nice for tree/table/combobox etc.

darrellmeyer
18 Jul 2008, 12:30 PM
I have added a new SimpleComboBox component. It is a ComboBox subclass that can work with simple types.


SimpleComboBox<String> combo = new SimpleComboBox<String>();
combo.add("Darrell");
combo.add("Maro");
combo.add("Alec");
combo.add("Lia");
combo.remove("Lia");
combo.setSimpleValue("Maro");The ComboBox store will hold SimpleComboValue instances which have getters and setters for the value they are wrapping:


combo.addSelectionChangedListener(new SelectionChangedListener<SimpleComboValue>() {
@Override
public void selectionChanged(SelectionChangedEvent<SimpleComboValue> se) {
System.out.println(se.getSelectedItem().getValue());
}
});This code is in SVN. Take a look and let me know if you have any feedback on the approach.

gslender
18 Jul 2008, 2:35 PM
Darrell, the code won't ANT build/compile using JDK6up7

Build fails with type parameters of <X>X cannot be determined; no unique maximal instance exists for type variable X with upper bounds T,java.lang.Object

JDK bug exists http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6302954

Luckily a workaround exists...

Line 29 of SimpleComboValue

return (T) get("value");


Line 82 of SimpleComboBox

return getValue().<T>get("value");