RR: making extracting and setting widget data easier

15 views
Skip to first unread message

Arthur Kalmenson

unread,
Oct 3, 2008, 10:55:04 AM10/3/08
to Google Web Toolkit Contributors
Hello every,

Just a little backgrounder for this RR. For some time now, a coworker
and I have been working on and off on a library/framework to simplify
creation of GWT applications, specifically those that cover most of
our use cases. For the most part, the applications we build involve
filling out rather large forms, retrieving data, generating reports,
etc. Building these large forms by hand is very tedious, so we created
an open source project called Mount Sinai Hospital Application Builder
(mshab) which you can find here: http://code.google.com/p/mshab/.

I started to overhaul the project to make it easier to use and easier
to extend. As I started the overhaul, I noticed that the incubator
started to get populated with a lot of similar widgets and libraries
that I was redeveloping. I contacted Emily Crutcher about the
Validation aspect and we ended up talking a bit about the incubator. I
decided that it'll be best to try to commit back to the incubator so
we could avoid having to throw away our code after the incubator
implemented the same ideas. I'll start making RRs about the various
parts that we were working on to get feedback and hopefully
incorporate it into the incubator.

Now, to the meat of the post. Right now, extracting data from widgets
is very different depending on the widget. From a TextBox, you call
textBox.getText(). For a ListBox you call
listBox.getValue(listBox.getSelectedItem()). Setting the data is
different too, and sometimes pretty "complex" (ListBox involves a
loop, etc). Therefore, I'm proposing a common interface that wraps
around core GWT widgets and provides one way to extract and set data
to widgets. There are a number of use cases where this can be applied.
Some good examples are validation and simple data binding.

The interface is a straight forward generic interface that works with
a generic widget and a generic data type (comments removed):

public interface DataManager<T, S> {

public S getData(T widget);

public void setData(T widget, S data);
}

Here's an example of how it would be used to manage TextBoxBase
widgets.

public class TextBoxBaseDataManager implements
DataManager<TextBoxBase, String> {

public String getData(TextBoxBase widget) {
return widget.getText();
}

public void setData(TextBoxBase widget, String data) {
widget.setText(data);
}
}

To help developers easily get the appropriate DataManager for a
specific widget, I created a DataManagerCollection interface where you
can get the specific DataManager for a given widget and then start
working with it. The developer can either use existing
DataManagerCollection implementations or wire their own.

public interface DataManagerCollection {

public boolean hasDataManager(Widget widget);

public DataManager<?, ?> getDataManager(Widget widget);

public void setDataManager(Widget widget, DataManager<?, ?>
dataManager);
}

We're currently working on creating wrappers for all the core GWT
widgets and the incubator ones. Feedback would be much appreciated.
Thank you for your time.

Best regards,
Arthur Kalmenson

Isaac Truett

unread,
Oct 3, 2008, 11:06:21 AM10/3/08
to Google-Web-Tool...@googlegroups.com
Why wrappers? Why not have the widgets simply implement a HasData interface?

public interface HasData<T> {
public T getData();
public void setData(T data);
}

Maybe I'm just not seeing your use case.

Emily Crutcher

unread,
Oct 3, 2008, 11:25:58 AM10/3/08
to Google-Web-Tool...@googlegroups.com
Having worked on similar projects, I am very enthusiastic about the idea of creating a full gwt forms module,  as apart from it being a true pain in the neck to create them by hand, improving the overall quality of such forms will, in the long term, save lives, so I'm looking forward to this work.  

-------------------

The same widgets might be used to get/set different data types and it separates the presentation logic from the data model, so separating the two seems to make some sense. On the other hand, it means that there is no simple interface that can be used when you actually do have data model objects:

So what if we combined the two:

 
public interface HasData<T> {
       public T getData();
       public void setData(T data);
}

then:

public interface DataManager<T, S extends HasData>   {
     public HasData getData(T widget);
--
"There are only 10 types of people in the world: Those who understand binary, and those who don't"

Arthur Kalmenson

unread,
Oct 3, 2008, 11:59:13 AM10/3/08
to Google Web Toolkit Contributors
> > Why wrappers? Why not have the widgets simply implement a HasData
> > interface?

As Emily pointed out, this helps separate presentation logic from the
data model. Furthermore, there are cases when you want to get data out
of the same widget in different ways. A good example is a DataManager
for ListBoxes. A simple implementation would look something like this:

public class ListBoxDataManager implements DataManager<ListBox,
String> {
public String getData(ListBox widget) {
String result = null;
if (widget.getSelectedIndex() > -1) {
result = widget.getValue(widget.getSelectedIndex());
}
return result;
}

public void setData(ListBox widget, String data) {

// go through the list of
for (int i = 0; i < widget.getItemCount(); i++) {
if (widget.getValue(i).equals(data)) {
widget.setSelectedIndex(i);
break;
}
}
}
}

However, if you're working with a lot of ListBoxes that have a default
value set at index 0, you might create a different DataManager to
handle that particular use case and return null if the first index is
selected.

> The same widgets might be used to get/set different data types and it
> separates the presentation logic from the data model, so separating the two
> seems to make some sense. On the other hand, it means that there is no
> simple interface that can be used when you actually do have data model
> objects:
>
> So what if we combined the two:
>
> public interface HasData<T> {
> public T getData();
> public void setData(T data);
>
> }
>
> then:
>
> public interface DataManager<T, S extends HasData> {
> public HasData getData(T widget);
> public void setData(T widget, S data);

That's a good point but I'm not sure I really understand the sample
code. Is the idea that if I have a data model Widget, it would
implement the HasData interface? It seems that S would end up being
the same as T in the generic implementation. I'll try to implement
this to get an idea what you mean.

Best regards,
Arthur Kalmenson
> > On Fri, Oct 3, 2008 at 10:55 AM, Arthur Kalmenson <arthur.k...@gmail.com>

Isaac Truett

unread,
Oct 3, 2008, 12:02:29 PM10/3/08
to Google-Web-Tool...@googlegroups.com
Let me offer a use case and see if that helps. If I'm just off base
here, do please let me know.

First, some definitions (please excuse the crudity of these models. I
didn't have time to build them to scale):

public interface HasData<T> {
public T getData();
public void setData(T data);
}

public abstract class Form<T> extends Composite implements HasData<T> {
// Some reusable form-y stuff here.
}

public abstract class ContrivedReadOnlyWidget<T> extends Composite
implements HasData<T> {
// A contrived example of something else that HasData.
}

public class Foo {
// My data
}

public class LoadFooCommand implements Command {
private String fooId;
private HasData<T> dataWidget;

public LoadFooCommand(String fooId, HasData<Foo> dataWidget) {
this.fooId = fooId;
this.dataWidget = dataWidget;
}

// Load the Foo with the specified into the dataWidget.
public void execute() {
Foo myFoo = getFoo(fooId);
dataWidget.setData(myFoo);
}
}

I have a pattern very close to this in my current project. Basically,
I can reuse simple Commands to do things like populate forms or
display pages with existing database records.

What would you do with the DataManager interface in this example? Or
if it doesn't apply in this example, what would be an example of how
it would be used?

Ray Ryan

unread,
Oct 3, 2008, 12:07:54 PM10/3/08
to Google-Web-Tool...@googlegroups.com
I'm with Isaac. I think the case for teaching our Widgets to implement HasData<T> is really clear cut (especially if they also accept DataChange listeners). The DataManager is a bit harder to justify, and anyway trivial for folks to implement on their own.

rjrjr

Emily Crutcher

unread,
Oct 3, 2008, 12:26:52 PM10/3/08
to Google-Web-Tool...@googlegroups.com
Yes, I think 90% of the time something like this is what you'd want. 

The place I can see the manager being useful is more to help create/associate model objects with widgets, which would only be something you'd need for reasonably complex applications.
 
interface QuestionAnswerPair {
  Question getQuestion();
  Answer getAnswer();
}


class QuestionAnswerManager implements DataManager<QuestionAnswerPair, HasText & HasId> {
}

public abstract class MyTextQuestion extends Composite{
   QuestionAnswerPair model =  getQuestionPairManager().getData(this);
   ...

Ian Petersen

unread,
Oct 3, 2008, 12:27:11 PM10/3/08
to Google-Web-Tool...@googlegroups.com
On Fri, Oct 3, 2008 at 12:07 PM, Ray Ryan <rj...@google.com> wrote:
> I'm with Isaac. I think the case for teaching our Widgets to implement
> HasData<T> is really clear cut (especially if they also accept DataChange
> listeners). The DataManager is a bit harder to justify, and anyway trivial
> for folks to implement on their own.

I'm not with Isaac. My first experience working with data binding was
as a co-op student working on the UI team on the Eclipse project at
OTI. That was a very educational co-op term! Eclipse, at least in
version 2--I've lost track since then, has a very clear separation
between SWT, the widget kit, and JFace, the "data binding" library
that sits on top of SWT.

In my mind, a Widget has a specific job to do--get displayed in an
application and, when appropriate, react to user manipulation.
Teaching basic widgets to know about "data" is a bad idea, IMO,
because it makes basic widgets too complicated. It also puts a lot of
pressure on programmers to use the data binding model that's baked
into the widgets, even if that model doesn't really suit a given
application. In fact, I think Isaac's comments may be an example of
this--he's built himself a model for doing data binding and, at first
blush, it looks like it doesn't match with Arthur's. It also seems
like neither Arthur's nor Isaac's model fits with the model that I
built and am frantically documenting in preparation for releasing
here. If any of our models is chosen as The GWT Way and baked into
the basic widgets, the others are probably out of luck. Instead, I
think a data binding library should be built on top of a widget
library for two main reasons: you can switch data binding libraries
more easily and, perhaps more importantly, you don't have to use any
data binding library at all.

Ian

Ray Ryan

unread,
Oct 3, 2008, 12:38:52 PM10/3/08
to Google-Web-Tool...@googlegroups.com
I think you're reading too much into the word "data." All I'm after is a uniform way to find out what value a widget is showing, without my controller having to know specifically what widget it is. I think that can be done in a minimalist, low level way that doesn't conflict with various data binding approaches. 

Suppose that you could already rely on TextField implements HasValue<String>, CheckBox implements HasValue<Boolean>. How would that interfere with the work you're doing now? Might it simplify it any?

rjrjr

Emily Crutcher

unread,
Oct 3, 2008, 12:42:53 PM10/3/08
to Google-Web-Tool...@googlegroups.com
I was thinking of a slightly more complex use case where you might have full model objects.

public class ListBoxModel implements HasValue<ListItem>{
  ...
}
 

public class ListBoxDataManager implements DataManager<ListBox, ListBoxModel>{
  ...
}


public class MyListBox extends Composite  implements HasValue<ListItem>{
      private ListBox wrappedWidget = new ListBox();
      private ListBoxModel model = ListBoxDataManager().getCurrentManager().get(this);
 
      ListItem getValue() {
        model.getValue();
    }
}
 

Isaac Truett

unread,
Oct 3, 2008, 12:47:15 PM10/3/08
to Google-Web-Tool...@googlegroups.com
I agree with Ian about the benefits of having data binding libraries
independent of the GWT widget library. I'm not trying to push my own
data binding scheme. My proposal of a HasData interface was to address
this point from Arthur's original post:

> Right now, extracting data from widgets is very different depending on the widget.

Most of the Widgets could implement HasData<String> and solve this
problem (See Ray's post while I was writing this). DataManagers and
complex but separated Model/View schemes could be based on that.
HasData is a tool for normalizing APIs which would make building data
binding, validation, and other libraries easier.

Ian Petersen

unread,
Oct 3, 2008, 12:52:47 PM10/3/08
to Google-Web-Tool...@googlegroups.com
Isaac has also replied while I'm writing this. I now see that Isaac's
and Ray's suggestions are not as all-encompassing as I originally
interpreted them. I'm just stepping out for lunch now, though, so I
don't really have time to think about this properly or reply with the
thoughtfulness that's due. Maybe after lunch I'll extend what
follows.

On Fri, Oct 3, 2008 at 12:38 PM, Ray Ryan <rj...@google.com> wrote:
> I think you're reading too much into the word "data."

That might be true....

> Suppose that you could already rely on TextField implements
> HasValue<String>, CheckBox implements HasValue<Boolean>. How would that
> interfere with the work you're doing now? Might it simplify it any?

Perhaps. What would ListBox implement? HasData<String> or
HasData<List<String>> (ie. do we assume single-select or
multi-select)? Would Label implement HasData<String>? Does
HasData<T> imply SourcesChangeEvents (or the gen2 equivalent)? Would
it be useful to do something like the following? (I've done
essentially this in my library)

public interface DisplaysData<T> {

void setData(T data);
}

public interface HasData<T> extends DisplaysData<T> {

T getData();
}

Maybe Label would implement DisplaysData<String> while TextBox would
implement HasData<String>. DisplaysData<T> wouldn't imply
SourcesChangeEvents but HasData<T> might.

Ian

Isaac Truett

unread,
Oct 3, 2008, 1:09:36 PM10/3/08
to Google-Web-Tool...@googlegroups.com
> Perhaps. What would ListBox implement? HasData<String> or
> HasData<List<String>> (ie. do we assume single-select or
> multi-select)?

/**
* Gets the currently-selected item. If multiple items are selected, this
* method will return the first selected item ({@link #isItemSelected(int)}
* can be used to query individual items).
*
* @return the selected index, or <code>-1</code> if none is selected
*/
public int getSelectedIndex() {
return getSelectElement().getSelectedIndex();
}

To me, this indicates an existing single-select bias. On that basis, I
would say that ListBox implements HasValue<String>. Or...

interface HasValue<T> {
T getValue();
void setValue(T value);
}

interface HasValues<Collections<T>> extends HasValue<T> {
Collection<T> getValues();
void setValues(Collection<T> values);
}

I'm shooting from the hip there, but at first glance it makes sense.
Then ListBox implements HasValues<String> and you get singular methods
which return the first selected item or set the only selected
(removing any other selections) item. The plural methods obviously get
and set all selected items.

> Would Label implement HasData<String>?

Yes. HasData<String> would essentially replace HasText, wouldn't it?

Emily Crutcher

unread,
Oct 3, 2008, 1:25:13 PM10/3/08
to Google-Web-Tool...@googlegroups.com, Bob Vawter
I think this basic idea makes sense, though I might argue that we might want to create a DropDownListBox and a MultiSelectListBox  and deprecate list box, as the API for ListBox is hard to normalize this way.

However, at the same time, a more complex data binding API seems like it could be very useful as well. Maybe the trick is we should treat the two discusions seperately.

a) Create a HasValue<T>, potencially extending a HasReadOnlyValue<T> interface which is used even for base ui widgets. This one might make into 1.6 even.

b) Create a data binding framework that  binds widgets to more complex data.  It will probably not be ready for several months and should be very flexible.

Isaac Truett

unread,
Oct 3, 2008, 2:27:13 PM10/3/08
to Google-Web-Tool...@googlegroups.com
+1 what Emily said.

Ian Petersen

unread,
Oct 3, 2008, 2:33:54 PM10/3/08
to Google-Web-Tool...@googlegroups.com
On Fri, Oct 3, 2008 at 1:09 PM, Isaac Truett <itr...@gmail.com> wrote:
>> Would Label implement HasData<String>?
>
> Yes. HasData<String> would essentially replace HasText, wouldn't it?

(As an aside, if HasData<String> replaces HasText, perhaps HasText
should be "redefined" to extend HasData<String>.)

Ray talked about creating a "uniform way to find out what value a
widget is showing" and Isaac described HasData<T> as "a tool for
normalizing API". I think those are key ideas. As such, I think we
need to go one step further. HasData<T> should imply
SourcesChangeEvents, or maybe SourcesDataChangeEvents<T>. A TextBox
certainly HasData<String>, but I think it's equally important that the
user can change the data in the text box. Any data binding library is
going to have to listen for updates from the widgets that are capable
of editing a value, and I think normalizing the notification of those
changes is at least as useful as normalizing the display of values.
In particular, I think CheckBox would benefit from
SourcesDataChangeEvents<Boolean>.

If you buy my argument that HasData<T> needs to imply
SourcesDataChangeEvents<T>, then I think it follows that Label should
not implement HasData<T>. Something like HasReadOnlyData<T> (like
Emily suggested) would be necessary to bridge the gap between
"editors" and "viewers".

On a completely different note, I just noticed that RadioButton
inherits from CheckBox. Does it make sense for RadioButton to
implement HasData<Boolean>? To me, a collection of RadioButtons is
roughly equivalent to a single-select ListBox and, as such,
RadioButton implementing HasData<Boolean> is somewhat nonsensical,
whereas a collection of RadioButtons should probably implement
HasData<String>, or something similar.

Ian

Ian Petersen

unread,
Oct 3, 2008, 2:37:57 PM10/3/08
to Google-Web-Tool...@googlegroups.com
On Fri, Oct 3, 2008 at 1:25 PM, Emily Crutcher <e...@google.com> wrote:
> I think this basic idea makes sense, though I might argue that we might want
> to create a DropDownListBox and a MultiSelectListBox and deprecate list
> box, as the API for ListBox is hard to normalize this way.

Sorry to nitpick, but I hope that DropDownListBox is not the only way
to get a single-select list box--sometimes it's useful to have a
single-select list box that is not a drop-down. I'd be happy with
either SingleSelectListBox and DropDownListBox being sibling classes
or SingleSelectListBox having a way to toggle between drop-down and
not-drop-down modes.

+1 to everything else you said.

Ian

Arthur Kalmenson

unread,
Oct 3, 2008, 2:50:17 PM10/3/08
to Google Web Toolkit Contributors
Sorry for not getting a chance to respond earlier...

> However, at the same time, a more complex data binding API seems like it
> could be very useful as well. Maybe the trick is we should treat the two
> discusions seperately.

I agree completely.

> a) Create a HasValue<T>, potencially extending a HasReadOnlyValue<T>
> interface which is used even for base ui widgets. This one might make into
> 1.6 even.

I think that this idea is fine because the data extraction and setting
is simple for core GWT widgets. The main reason I didn't do it this
way, as I mentioned to Emily, was that I didn't want to mirror all the
core GWT widgets. If this makes it into 1.6, that would be great (if
it can appear in the trunk, I'll switch to trunk so I can use this).

However, for more complex widgets, I think a separation between data
management logic and the widget's primary role of displaying itself is
a good idea. As Ian said, building data bindings and data management
on top of widgets allows you to separate concern and roll your own
solutions (instead of subclassing and overriding Widgets). Therefore,
baking HasValue into the base Widgets makes customization a little
complex.

> b) Create a data binding framework that binds widgets to more complex
> data. It will probably not be ready for several months and should be very
> flexible.

I'll start another discussion about data binding since I think it's an
important and useful feature and should probably be included in
incubator if not in gwt. I was talking to papick in #gwt who created a
simple data binding library using generators. I'll try to see if he
can release his code, so we could potentially work from it.

Regards,
Arthur Kalmenson

Arthur Kalmenson

unread,
Oct 3, 2008, 2:59:41 PM10/3/08
to Google Web Toolkit Contributors
> If you buy my argument that HasData<T> needs to imply
> SourcesDataChangeEvents<T>, then I think it follows that Label should
> not implement HasData<T>. Something like HasReadOnlyData<T> (like
> Emily suggested) would be necessary to bridge the gap between
> "editors" and "viewers".

I agree 100%, the hasText interface is very confusing. Sometimes it's
used to represent text set by users (TextBox) as well as text set by
the application (Label). I think that a HasData<T> and
HasReadOnlyData<T> is a great idea. Implementing some
SourcesDataChangeEvents<T> interface will make it easier to do
validation and help make efficient data binding where the target bean
will only receive changed widgets.

> On a completely different note, I just noticed that RadioButton
> inherits from CheckBox. Does it make sense for RadioButton to
> implement HasData<Boolean>? To me, a collection of RadioButtons is
> roughly equivalent to a single-select ListBox and, as such,
> RadioButton implementing HasData<Boolean> is somewhat nonsensical,
> whereas a collection of RadioButtons should probably implement
> HasData<String>, or something similar.

I agree, it should be HasData<String>, but I think that RadioButton
should not be a single entity that's linked by a String group name (at
least not from the GWT side, I understand the JS side has to be like
that). I think that RadioButton should be RadioButtons and should act
more like ListBox where you can add additional choices. The current
RadioButton implementation is pretty low level and is rather close to
the way it's done in Javascript.

Regards,
Arthur Kalmenson

On Oct 3, 2:33 pm, "Ian Petersen" <ispet...@gmail.com> wrote:
Reply all
Reply to author
Forward
0 new messages