If you are following my blog you may have noticed that I invested some hours this weekend in Eclipse-Databinding and GWT.
It was Saturday in the evening when I got the Eclipse-Databinding working inside GWT and I started searching for a decent Table and TableTree-Widget (I looked at the code in the gwt-incubator but that didn’t made me happy). So I thought the RAP people are using Qooxdoo as the underlying JavaScript-UI library what would be if there was a GWT-Binding to this JavaScript-Lib using the GWT-native calling interface and so I started search for such a thing but apparently noone ever tried to write such a thing. So I started reading docs and studying libraries who use this native-calling interface – I’ve never written such a thing before – and voilá it was yesterday around lunch time when I had the first success because one of the GWT-Demos showed up.
The Java code for this small application looks like this:
public class Button extends QooxdooApp { @Override protected void run(QxAbstractGui application) { QxHBox box = new QxHBox(); box.setSpacing(10); QxComposite container = new QxComposite(box); container.setPadding(20); application.getRoot().add(container, QxOption.left(0), QxOption.top(0)); QxButton btn1 = new QxButton("Button A", "/icon/22/apps/media-video-player.png"); container.add(btn1); QxButton btn2 = new QxButton("Button B", "/icon/22/apps/internet-mail.png"); btn2.setEnabled(false); container.add(btn2); QxToggleButton btn3 = new QxToggleButton("Toggle Button", "/icon/22/apps/internet-web-browser.png"); btn3.focus(); container.add(btn3); QxRepeatButton btnRepeat = new QxRepeatButton(null,"/icon/22/actions/list-add.png"); container.add(btnRepeat); final QxLabel l1 = new QxLabel("0"); l1.setDecorator("main"); l1.setPadding(2, 4); l1.setBackgroundColor("white"); container.add(l1); btnRepeat.addExecuteHandler(new ExecuteHandler() { public void execute(ExecuteEvent executeEvent) { int tmp = Integer.parseInt(l1.getContent()) + 1; l1.setContent(tmp+""); } }); } }
and now compare it too the original source:
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2004-2008 1&1 Internet AG, Germany, http://www.1und1.de License: LGPL: http://www.gnu.org/licenses/lgpl.html EPL: http://www.eclipse.org/org/documents/epl-v10.php See the LICENSE file in the project's top-level directory for details. Authors: * Sebastian Werner (wpbasti) * Fabian Jakobs (fjakobs) ************************************************************************ */ /* ************************************************************************ #asset(qx/icon/${qx.icontheme}/22/apps/media-video-player.png) #asset(qx/icon/${qx.icontheme}/22/apps/internet-mail.png) #asset(qx/icon/${qx.icontheme}/22/apps/internet-web-browser.png) #asset(qx/icon/${qx.icontheme}/22/actions/list-add.png) ************************************************************************ */ qx.Class.define("demobrowser.demo.widget.Button", { extend : qx.application.Standalone, members : { main: function() { this.base(arguments); var box = new qx.ui.layout.HBox(); box.setSpacing(10); var container = new qx.ui.container.Composite(box); container.setPadding(20); this.getRoot().add(container, {left:0,top:0}); // Two normal buttons var btn1 = new qx.ui.form.Button("Button A", "icon/22/apps/media-video-player.png"); container.add(btn1); var btn2 = new qx.ui.form.Button("Button B", "icon/22/apps/internet-mail.png"); btn2.setEnabled(false); container.add(btn2); // Toggle Button var btn3 = new qx.ui.form.ToggleButton("Toggle Button", "icon/22/apps/internet-web-browser.png"); btn3.focus(); container.add(btn3); btn3.addListener("changeChecked", function(e) { this.debug("Checked: " + e.getData()); }, this); // Repeat Button var img1 = "icon/22/actions/list-add.png"; var btnRepeat = new qx.ui.form.RepeatButton(null, img1); container.add(btnRepeat); // Label var l1 = new qx.ui.basic.Label("0"); l1.setDecorator("main"); l1.setPadding(2, 4); l1.setBackgroundColor("white"); container.add(l1); // Listener btnRepeat.addListener("execute", function() { var tempValue = parseInt(l1.getContent()) + 1; l1.setContent(tempValue.toString()); }); } } });
Afterwards I went outdoors because the weather was just too nice to stay inside but because of my great success in the morning I sat down and implemented a few more widgets to show you the GWT-Databinding example from Saturdays post running on Qooxdoo-GWT.
public class TextLabelBinding extends QooxdooApp { @Override protected void run(QxAbstractGui application) { final QxLabel titleLabel = new QxLabel(""); final QxTextField firstNameField = new QxTextField(""); final QxTextField lastNameField = new QxTextField(""); QxVBox box = new QxVBox(); box.setSpacing(10); QxComposite container = new QxComposite(box); container.setPadding(20); container.add(titleLabel); container.add(firstNameField); container.add(lastNameField); application.getRoot().add(container, QxOption.left(0), QxOption.top(0)); final Person p = new Person(); p.setFirstname("Tom"); p.setLastname("Schindl"); DataBindingContext dbc = new DataBindingContext(QxObservables.getRealm()); QxIWidgetValueProperty uiProp = QxWidgetProperties.text(); dbc.bindValue(uiProp.observe(firstNameField), UBeansObservables.observeValue(QxObservables.getRealm(), p, Person.FIRST_NAME)); dbc.bindValue(uiProp.observe(lastNameField), UBeansObservables.observeValue(QxObservables.getRealm(), p, Person.LAST_NAME)); ComputedValue titleValue = new ComputedValue(QxObservables.getRealm()) { private IObservableValue last = UBeansObservables.observeValue(QxObservables.getRealm(), p, Person.LAST_NAME); private IObservableValue first = UBeansObservables.observeValue(QxObservables.getRealm(), p, Person.FIRST_NAME); @Override protected Object calculate() { return last.getValue().toString().toUpperCase() + ", " + first.getValue(); } }; dbc.bindValue(uiProp.observe(titleLabel), titleValue); } }
I’m going to look at the more complex controls when having the next free time slot but for now this is just plain cool, isn’t it?
That’s awesome Tom,
do you plan to build on this or is it more a (cool) tech demo? I’ve played with GWT wrappers for qooxdoo some time ago. Maybe you remember our presentation at the ESE last year. However I’ve hit some blockers, which stopped me from writing full GWT wrappers for qooxdoo. If you plan to work further on this I can share my experience.
Yes I’m going to because I’m unhappy with all other toolkits until now so if we share our experience I’m happy to do so. I don’t know where you are from but I’m going to be in Karlsruhe on 7.7. for the Eclipse Developer Day. so we probably can meet in person.
I think I should clarify this a bit. I’m going to invest time to go on for sure but I can’t promise how much time I can invest without having an immediate business case behind or getting paid for it some way or another.
Tom, that’s perfect. We’re in Karlsruhe as well, so lets meet before or after the EADD. We’ll figure out the schedule by mail/fon.
Hi Tom, that is indeed very cool. 😉
I just sent you an email, so maybe we can collaborate on a qooxdoo-GWT project (BTW, we’ve also created such a GWT-based proof-of-concept a while ago, even have a non-GWT solution called the qooxdoo Web Toolkit (QWT)).
Should you choose to implement such a qooxdoo-gwt-toolkit, I would like to ask you to strongly consider NOT using the JSNI/js-wrapper route. A much higher quality/speed can be achieved by implementing the DOM-structure that qooxdoo creates in GWT components (the way that GXT is done). In any other case it will be necessary to include the underlying js file which is what makes GWT-Ext, SmartGWT, etc so slow, because the compiler cannot optimize and shrink it, it needs to be there in its entirety up front, which is not optimal.
I agree with you that this would be the best option but also the one with most work and as stated before I’m uncertain whether I can invest the time. It also means that one has to port all fixes, … manually which is probably going to be a maintance nightmare 😦