QxWT explained Part 2


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

This creates an UI like this:

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.

This entry was posted in QxWT. Bookmark the permalink.

3 Responses to QxWT explained Part 2

  1. Pingback: QxWT explained Part 3 « Tomsondev Blog

  2. Pingback: QxWT explained Part 4 « Tomsondev Blog

  3. Pingback: QxViewers – The first steps towards a UFaceKit-Webport « Tomsondev Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s