Thursday, April 29, 2010

Extending SmartGWT widgets to be UIBinder-compliant

SmartGWT canvas widgets can seldom share space with GWT widgets. The SmartGWT canvas would push itself in-front to obstruct the visibility of GWT widgets. To share a space between the two sets of widgets, the page design needs to carefully avoid having GWT widgets intersecting into SmartGWT canvas, vice versa. Especially that any part of a GWT sub-menu or pop-up that pops into SmartGWT canvas space would not be visible.

Having understood this constraint, this article describes placing extension wrappers around SmartGWT canvas widgets to allow them to be used as UIBinder widgets. Also note that certain newer SmartGWT widgets do not work well with UIBinder.

As described in a previous article, any GWT to be used as UIBinder widgets should
be
  • an extension class of com.google.gwt.user.client.ui.Widget and
  • implement com.google.gwt.user.client.ui.HasWidgets.

The first SmartGWT widget to extend is, of course, com.smartgwt.client.widgets.Canvas, because all SmartGWT has to be placed onto a Canvas.

import org.synthful.smartgwt.client.HasWidgetsUtil;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
import com.smartgwt.client.widgets.Canvas;

public class UICanvas
    extends Canvas
    implements HasWidgets
{
    @Override
    public void add(Widget w) {
        super.addChild(w);
    }

    @Override
    public Iterator<Widget> iterator() {
        return HasWidgetsUtil.iterator(this);
    }

    @Override
    public boolean remove(Widget w) {
        return HasWidgetsUtil.remove(this, w);
    }

}
Notice the HasWidgetsUtil import highlighted in crimson. HasWidgetsUtil contains common static methods which could be used in most wrappers.

For a Canvas object that does not inherit from com.google.gwt.user.client.ui.Widget, we need to wrap it with a class that extends Widget and expose all the methods of that Canvas object. For example, while com.smartgwt.client.widgets.tab.TabSet inherits Widget, com.smartgwt.client.widgets.tab.Tab does not.

Wrapping Tabset is as simple as wrapping Canvas:

public class UITabset
    extends TabSet
    implements HasWidgets
{   
    @Override
    public void add(Widget w){
        if (w instanceof UITab)
            super.addTab(((UITab)w).tab);
        else
            super.addChild(w);
    }
   
    @Override
    public Iterator<Widget> iterator(){
        return HasWidgetsUtil.iterator(this);
    }

    @Override
    public boolean remove(Widget w){
        return HasWidgetsUtil.remove(this, w);
    }
}
However, to be able to use UIBinder to assign a Tab as a child of a Tabset, we need to wrap the Tab class this way:

package holymoly.smartgwt.ui

import java.util.ArrayList;
import java.util.Iterator;
import org.synthful.smartgwt.client.HasWidgetsUtil;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.tab.Tab;

public class UITab
    extends Widget
    implements HasWidgets
{
    public UITab(){
        this.tab = new Tab();
    }
       
    public void add(Canvas w){
        if (this.canvas==null){
                this.canvas = (Canvas)w;
                tab.setPane(this.canvas);
            }
    }
   
    @Override
    public void add(Widget w){
        try{
            this.add((Canvas)w);
        }
        catch(Exception e){}
    }
   
    @Override
    public void clear()    {
    }
   
    @Override
    public Iterator iterator()    {
        ArrayList<Widget> wx = new ArrayList();
        wx.add(this.canvas);
        return wx.iterator();
    }

    @Override
    public boolean remove(Widget w){
        return HasWidgetsUtil.remove(this, w);
    }

    public void setCloseable(boolean closeable){
        this.tab.setCanClose(closeable);
    }
   
    public void setCloseIcon(String closeIcon){
        this.tab.setCloseIcon(closeIcon);
    }
   
    public void setCloseIconSize(String closeIconSize){
        try{
            int z = Integer.parseInt(closeIconSize);
            this.tab.setCloseIconSize(z);
        }
        catch (Exception e){}
    }
   
    public void setDisabled(boolean disabled){
        this.tab.setDisabled(disabled);
    }
   
    public void setTitle(String title){
        this.tab.setTitle(title);
    }
   
    public void setWidth(String width){
        try{
            int z = Integer.parseInt(width);
            this.tab.setWidth(z);
        }
        catch (Exception e){}
    }
   
   
    final protected Tab tab;
    private Canvas canvas;
}

Now we could comfortably use these SmartGWT widgets with UIBinder:
<ui:uibinder
  xmlns:ui="urn:ui:com.google.gwt.uibinder"
  xmlns:z="urn:import:holymoly.smartgwt.ui"
  xmlns:g="urn:import:com.google.gwt.user.client.ui">
  <z:UICanvas ui:field="canvas">
   <z:UITabset ui:field="tabset">
    <z:UITab ui:field="tab1"> closeable="true"
     closeIcon="{someResource.someicon}"
     <g:Label ui:field="tab1content">
      Hello Galaticals!
     </g:Label>
    </z:UITab>
   </z:UITabset>
 </z:UICanvas>
</ui:uibinder>

More examples are found at
http://code.google.com/p/synthfuljava/source/browse/#svn/trunk/gwt/smartgwt.

5 comments: