In my last blog post I started explaining how QxWT adopters get support from us in release 1.0.0.2 (due end of February). We are going more into detail in this blog post.
Let’s once more recap what we are trying to achieve:
- Generated qooxdoo class for domain model usage (e.g. when working with databinding and forms)
- Extend exisiting qooxdoo classes
Since the last blog post the I added some more features so let’s look at the Annotations I presented in my last blog:
/** * Definition of a Qooxdoo-class */ @Target(ElementType.TYPE) public @interface QxClass { /** * @return Java super class */ String javaSuperClass() default "org.ufacekit.qx.wrapper.core.QxObject"; /** * @return javascript base class */ String jsBaseClass() default "qx.core.Object"; /** * @return the fully qualified class name of the js-class generated */ String jsClassName() default "N/A"; /** * @return the properties */ QxProperty[] properties(); }
and the property definition:
/** * A property of a qooxdoo object */ @Retention(RetentionPolicy.SOURCE) public @interface QxProperty { /** * @return name of the property */ String name(); /** * @return the value to check for e.g. String, ... */ String check() default "N/A"; /** * @return the event */ String event() default "N/A"; /** * @return whether property can be null */ boolean nullable() default false; /** * @return initial value */ String init() default "N/A"; /** * @return the class to wrap the init value in */ String initQxClass() default "N/A"; /** * @return validate function to call */ String validate() default "N/A"; /** * @return the method called when the value is applied */ String apply() default "N/A"; }
The information in the property are the ones one can use to when defining a class property.
We are now ready to address the first use case for and showing you an example how it is used in a demo:
Step 1: Define the domain interface
public interface Person extends IQxObject { public String getName(); public void setName(String name); public String getEmote(); public void setEmote(String emote); public boolean isOnline(); public void setOnline(boolean online); public void toggleOnline(); }
Step 2: Annotate the interface
@QxClass(properties = { @QxProperty(check = "String", event = "changeName", name = "name", nullable = true), @QxProperty(check = "String", event = "changeEmote", name = "emote"), @QxProperty(check = "Boolean", event = "changeOnline", name = "online", init = "true") }) public interface Person extends IQxObject { // ...
Step 3: Use the annotated interface in your GWT-Application
// names String[] names = { "Max", "Jakob", "Tim", "Jack", "Dan", "Dustin","Karl", "Jim" }; String[] emotes = { "embarrassed", "kiss", "plain", "sad", "surprise","angel" }; // create the data Person[] rawData = new Person[20]; for (int i = 0; i < 20; i++) { Person person = GWT.create(Person.class); person.setName(names[i % names.length]); person.setEmote(emotes[i% emotes.length]); person.setOnline(i % 3 == 0); rawData[i] = person; }
Easy isn’t it? Yes it is but how does it work? We’ve never defined a class which implements the Person interface nor there are things like dynamic proxy available in GWT. The important call is GWT.create(Person.class) which triggers the GWT-Generator which allows one to generate Javacode.
In case of the above the code generated looks like this:
package org.ufacekit.qx.wrapper.demo.client.demobrowser.demo.data.model; public class Person_Gen extends org.ufacekit.qx.wrapper.core.QxObject implements org.ufacekit.qx.wrapper.demo.client.demobrowser.demo.data.model.Person { static { defineQxClass(); } private static native com.google.gwt.core.client.JavaScriptObject defineQxClass() /*-{ $wnd.qx.Class.define("qxwt.org.ufacekit.qx.wrapper.demo.client.demobrowser.demo.data.model.Person_Gen", { extend : $wnd.qx.core.Object, properties : { name: { check : "String", event : "changeName", nullable : true }, emote: { check : "String", event : "changeEmote", nullable : false }, online: { check : "Boolean", event : "changeOnline", init : true, nullable : false } } }); }-*/; private static native com.google.gwt.core.client.JavaScriptObject createNativeObject() /*-{ var rv = new $wnd.qxwt.org.ufacekit.qx.wrapper.demo.client.demobrowser.demo.data.model.Person_Gen(); return rv; }-*/; public Person_Gen() { super(createNativeObject()); } public java.lang.String getName() { return native_getName( getNativeObject() ); } private native java.lang.String native_getName(com.google.gwt.core.client.JavaScriptObject self)/*-{ return self.getName(); }-*/; public void setName(java.lang.String name) { native_setName( getNativeObject() ,name); } private native void native_setName(com.google.gwt.core.client.JavaScriptObject self,java.lang.String name)/*-{ return self.getName(); }-*/; public void setName(java.lang.String name) { native_setName( getNativeObject() ,name); } private native void native_setName(com.google.gwt.core.client.JavaScriptObject self,java.lang.String name)/*-{ self.setName(name == null ? null : name + ""); }-*/; public java.lang.String getEmote() { return native_getEmote( getNativeObject() ); } private native java.lang.String native_getEmote(com.google.gwt.core.client.JavaScriptObject self)/*-{ return self.getEmote(); }-*/; public void setEmote(java.lang.String emote) { native_setEmote( getNativeObject() ,emote); } private native void native_setEmote(com.google.gwt.core.client.JavaScriptObject self,java.lang.String emote)/*-{ self.setEmote(emote == null ? null : emote + ""); }-*/; public boolean isOnline() { return native_isOnline( getNativeObject() ); } private native boolean native_isOnline(com.google.gwt.core.client.JavaScriptObject self)/*-{ return self.isOnline(); }-*/; public void setOnline(boolean online) { native_setOnline( getNativeObject() ,online); } private native void native_setOnline(com.google.gwt.core.client.JavaScriptObject self,boolean online)/*-{ self.setOnline(online); }-*/; public void toggleOnline() { native_toggleOnline( getNativeObject() ); } private native void native_toggleOnline(com.google.gwt.core.client.JavaScriptObject self)/*-{ self.toggleOnline(); }-*/; }
A lot of code right! So what you are getting back from the call to GWT.create(Person.class) is an instance from this dynamically generated class named Person_Gen (If you are interested how this works you should take a look at QxClassGenerator.java).
The nice thing is that we can now directly use such an instance or list of instances as input for qooxdoo-Databinding:
QxArray<Person> p = QxArray.breed(rawData); final QxDataArray<Person> data = new QxDataArray<Person>(p); // create the widgets QxFormList<QxFormListItem> list = new QxFormList<QxFormListItem>(); list.setWidth(150); // add the widgets to the document container.add(list, QxOption.leftTop(10, 80)); // create the controller QxListController<Person,QxFormCheckBox> controller = new QxListController<Person,QxFormCheckBox>(null, list); Delegate<QxListController<Person,QxFormCheckBox>, QxFormCheckBox, Person> delegate = new Delegate<QxListController<Person,QxFormCheckBox>, QxFormCheckBox, Person>() { public int delegatesMask() { return DEFAULT; } public boolean filter(Person data) { return true; } public QxFormCheckBox createItem() { return new QxFormCheckBox(); } public void configureItem(QxFormCheckBox item) { item.setPadding(3); } public void bindItem(QxListController<Person,QxFormCheckBox> controller, QxFormCheckBox item, int id) { controller.bindProperty("name", "label", item, id); controller.bindProperty("online", "value", item, id); controller.bindPropertyReverse("online", "value", item, id); } }; controller.setDelegate(delegate); controller.setModel(data);
I think this example shows how powerful the GWT-Generator features is. We have now seen how we can use it to solve our first use case and in the next blog post will discuss how the GWT-Generator helps us solve the second use case “Extending existing qooxdoo classes”.
If you’d like to follow my progress towards 1.0.0.2 you can take a look at the extended demos.
Pingback: QxWT explained Part 3 « Tomsondev Blog
Pingback: QxWT explained Part 4 « Tomsondev Blog
Pingback: QxViewers – The first steps towards a UFaceKit-Webport « Tomsondev Blog