GXT ModelData Cloning/copy

Clean way:

 public static void cloneModelData(ModelData source, ModelData dest) {
       dest= new BaseModelData(source.getProperties());
    }

Another way if you need to do any modification during looping.

 public static void cloneModelData(ModelData source, ModelData dest) {
 Iterator iterator = source.getPropertyNames().iterator();
 while (iterator.hasNext()) {
 String key = iterator.next();
 dest.set(key, source.get(key));
 }
 }

FroM HERE

Advertisements

gxt panel scroll with mouse scroll

Stick div to top of page when start scrolling

the problem is similar to THIS . It is something like a “Stick div to top of page when start scrolling”.

In the above link, a lot of solutions are for jQuery. I need the gxt/gwt way.

 

gwt/gxt

In gwt we have scrollListener which can be used to achieve this by overwriting the onScroll() method. Doing it this way might make our app slow sometimes.

In GXT we have the Window.ScrollHandler().

something like:

com.google.gwt.user.client.Window.addWindowScrollHandler(new Window.ScrollHandler() {
            @Override
            public void onWindowScroll(Window.ScrollEvent event) {
                int topPosition = event.getScrollTop();
                boolean hasTopStyle = westPanel.getStyleName().contains(resources.css().westPanelTop());
                if (topPosition > 97 && !hasTopStyle) {
                    westPanel.addStyleName(resources.css().westPanelTop());
                }
                if(topPosition <= 97 && hasTopStyle){
                    westPanel.removeStyleName(resources.css().westPanelTop());
                }
            }
        });

My banner has a height of 97.
for the “westPanelTop” css, we just need to add a fixed to it.

.west-panel-top{
    position: fixed !important;
}

GXT RowLayout

Most of the time I use FitLayout as my panel layout data in GXT. However when it comes to a panel contains many other panels, Fitlayout might not be the best solution. So the RowLayout come into scene.

It will like it:

centerPanel.add(actionPanel, new RowData(1, -1, new Margins(4)));
centerPanel.add(userActionPanel, new RowData(1, 1, new Margins(4)));

 

Problem: here all the panels use RowLayout. if content in “userActionPanel” has some collapsible panel, after resize the scroll bar will not be there when content is out of the browser.

 

I was confused by the constructor. The margin part which is pretty much like the way used in other layout data,  is easy to understand. However the 1 and -1 looks odd.

According to the Doc:

  • Values less than or equal to 1 are treated as percentages, with 1 = 100%.
  • Values greater than 1 are treated as pixels.
  • Values equal to Style.DEFAULT (-1) will use the component’s computed height.

If we use Vertical orientation, the layoutVertical() will be called and it iterates all the child component and call setSize for them. This way, if any of the component is using 1 as height in the constructor. it will get an actual height value which will prevent the scroll bar from appearing when content get out of the browser window. Hence, my preference is using -1 all the time.

gxt panel resize

option 1 ViewPort

ViewPort will listen to resize event and automatically reset the size. However it seems that view port does not support the scroll very well though it also extends the LayoutContainer.

option2 addResizeHandler

without adding resizeHandler (I think listener is deprecated), the widgets in regular LayoutContainer do not resize automatically.
Therefore we need to add it explicitly. I put it directly in the onRender(), seems to work fine:

com.google.gwt.user.client.Window.addResizeHandler(new ResizeHandler() {
@Override
public void onResize(com.google.gwt.event.logical.shared.ResizeEvent event) {
setSize(com.google.gwt.user.client.Window.getClientWidth(), com.google.gwt.user.client.Window.getClientHeight() - 97);
}
});

The 97 is the banner size in my app.

PS: found a problem with using resizeHandler, which is once we set the height of the current window in the setSize method, the height is fixed, which will cause the problem that the scrollBar would never come out. Need to find a way to avoid set height but just set width. Currently i just use a workaround to set it as 2000px 😦

resourcebundle in gwt and gxt

GWT will search for the same package for resource.

just put the image/css or other resource in the resource folder with the same package route.

public interface Resources extends ClientBundle{
@Source(“images/addnew1616.png”)
ImageResource add();
}

For gxt2, widgets like Button accepts “AbstractImagePrototype”, so we use ClientBundles with ImageResources, we can convert by  using:

AbstractImagePrototype.create

 

 

For CSS, without UIBinder, remember to call the Resources.INSTANCE.xxxx().ensureInjected();

If you use UiBinder the call to ensureInjected is provided by the tag ui:with. For any other css you are using in a client bundle (i.e. legacy css excluded) and that are not declared in a ui:with block, you have to call ensureInjected explicitly.

set tooltip for disabled button in gwt

In my recent project, I need to set tooltip for disabled button so that user can get the info why this button is disabled and what action to take in order to enable it.

As we know the disabled button or menu item in gwt does not sink event, so even if we use setTooltip for the widget, when user hover on it he could not see the tooltip because we can not catch the hover event.

 

Swallow the click event seems to be the easiest way.

I was thinking of remove the handler for the widget instead of swallow the event. It turns out to be more complicated

A quick workaround is to create a new widget that subclasses GWT/GXT’s button/menuItem, adding the following override:

 

package org.finra.cdip.cobra.issuelist.client.widget;

import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.MenuEvent;
import com.extjs.gxt.ui.client.widget.menu.MenuItem;
import com.google.gwt.user.client.Event;

/**
 * Created with IntelliJ IDEA. User: Han Li Date: 5/20/13
 */
public class CobraMenuItem extends MenuItem
{
    private boolean customEnabled;

    public CobraMenuItem(String label)
    {
        super(label);
    }

    /**
     * add style to the disabled widget
     * @param enabled
     */
    @Override
    public void setEnabled(boolean enabled)
    {
        this.customEnabled = enabled;
        if (!enabled)
        {
            this.addStyleName(this.disabledStyle);
        }
        else
        {
            this.removeStyleName(this.disabledStyle);
            super.setEnabled(enabled);
        }
    }

    @Override
    public void onBrowserEvent(Event event)
    {
        if (event.getTypeInt() == Event.ONMOUSEDOWN || event.getTypeInt() == Event.ONCLICK)
        {
            if(!customEnabled)
            {
                // return directly so that no action would be taken.
                return;
            }
        }
        super.onBrowserEvent(event);
    }

    /**
     * overwrite the onClick by adding our own 'customEnabled' flag
     * @param be
     */
    @Override
    protected void onClick(ComponentEvent be) {
        be.stopEvent();
        MenuEvent me = new MenuEvent(parentMenu);
        me.setItem(this);
        me.setEvent(be.getEvent());
        if (customEnabled && !disabled && fireEvent(Events.Select, me)) {
            handleClick(be);
        }
    }
}

By adding these code, we can disable the click action as well as display a “disabled” widget to user.

 

 

The GWT/GXT rendering process

FROM HERE

The project I’m currently working on uses GWT and GXT and so I decided to dig into the frameworks to figure out how the both perform their magic of turning Java components into HTML elements. Since I’ve done the work, I thought I may as well share it incase anybody else is curious!

GWT Rendering

In order for GWT to render any component it MUST be added to the RootPanel, which is just a standard Panel component that wraps an actual existing element on the browsers HTML DOM; this can be see from the following hierarchy:

The RootPanel.get(String id) method, which will look up the specified element by id and return a RootPanel that wraps it, OR it will return a DefaultRootPanel which simply wraps the Body element (which is what you get if you call the RootPanel.get() method). The following code snippet from RootPanel.get(String) shows how all this is done:

    // Find the element that this RootPanel will wrap.
    Element elem = null;
    if (id != null) {
      if (null == (elem = DOM.getElementById(id))) {
        return null;
      }
    }

    // SNIP SNIP

    // Create the panel and put it in the map.
    if (elem == null) {
      // 'null' means use document's body element.
      rp = new DefaultRootPanel();
    } else {
      // Otherwise, wrap the existing element.
      rp = new RootPanel(elem);
    }

The process by which elements are added to this RootPanel is now the same for any standard panel, but before we get into that, we must understand two concepts in GWT regarding attachment, i.e the process by which a Widget becomes attached to the HTML DOM.

  • Logical Attachment : A component is said to be Logically Attached if it has been created (or even added to a parent), but has not been added to the physical DOM.
  • Physical Attachment : A component is physically attached when it has been added to the underlying DOM (and thus will be rendered by the browser)

Components are created using Logical Attachment (by, for example, creating and setting up new Panel objects), and then physically attached by adding them to a RootPanel. GXT extends on this idea to allow components to be lazily rendered as we’ll see later. For now lets have a look at how this all works using the simple GWT Label widget.

Widget Creation

Since GWT is Java, creating a new Widget is as simple as instantiating it’s constructor .i.e.

Label label = new Label("My Label");

And the constructor looks like so :

 public Label() {
    setElement(Document.get().createDivElement());
    setStyleName("gwt-Label");
  }

As we can see from the following code snippet, the label constructor calls into the special GWT DOM object in order to create a DIV element, this will be the actual element that will represent this Widget in the browser. Remember though that at this time the Element has not been physically attached to the underlying DOM, you could create thousands of these Label objects and none would currently appear in the browser.

The constructor calls the setElement method in order to inform the Widget what element it is going to use. This really calls down to the UIObject class which is the base of all, UI Objects in GWT. The element is simply registered for later use :

  protected void setElement(com.google.gwt.user.client.Element elem) {
    assert (element == null) : SETELEMENT_TWICE_ERROR;
    this.element = elem;
  }

Setting up the Widget

At this point in the process we have an empty label which isn’t going to look very interesting on an HTML page so now we need to give it some text. This is done via the aptly named setText method. If we have a look at Widget.setText we can see it calls the standard setInnerText the DIV element created earlier :

  public void setText(String text) {
    getElement().setInnerText(text);
  }

Rendering the Widget

We now have a label with some text which we know is actually a DIV element with some inner text, which remember is still only Logically attached; as far as the browser is concerned our Widget doesn’t currently exist. As said before, in order to physically attach the element we need to add it to a RootPanel, lets now look at the process our Label goes through when it’s added.

  1. RootPanel.add is called to add the Label to the underlying browser DOM
  2. ComplexPanel.add gets called to add the Label as a child of this panel (RootPanels are after all normal panels around a well known DOM element). This logically attaches the Label as a child of the panel, then physically attaches the Label as a child of the panels DOM Element.
  3. ComplexPanel.adopt is called which calls Label.setParent() to inform the label it now has a parent
  4. Label.setParent will call the onAttach method if this parent has been physically attached to the DOM (which it will have been since the panel wraps an existing DOM element)
  5. In the case of the Label there is no onAttach implementation, the DIV element was created when the Label was created and the innerText of the DIV is set as soon as setLabel is called on the Label; therefore in the case of our simple Label example, the rendering process is complete.

The following diagram shows (or at least attempts to show), how this all hangs together:

Click for bigger image

GXT Rendering

GXT or (EXT for GWT), is the widget framework I’m working with on my current project, which changes the rendering process to provide lazy rendering of the components. GXT doesn’t provide a Label component, but it does provide an Html component, so lets look at how GXT handles the rendering process.

  1. When the Html component is created, unlike the GWT Label, it DOESN’T create a DOM element, instead it acts just like a simple Java Object
  2. Html.setHtml(String) can be called at any time and, if the component hasn’t been attached (rendered in GXT speak), the html is simply stored in a String field.
  3. A GXT Component extends the GWT Widget class and therefore can be added to a standard RootPanel
  4. The rendering process is the same as above, however the GXT Component.onAttach overrides the Widget.onAttach in order to perform the GXT rendering process. It’s worth looking at the onAttach method in a little more detail because it solves a problem with lazy rendering of components.
  5. If you look at the previous diagram you’ll see that AbsolutePanel.add(Widget) retrieves the DOM element of the component (with getElement()) and passes it to the ComplexPanel.add(Widget, Element) method. Unfortunately in GXT we don’t want to create the DOM element until the onAttach method which is lower down the call stack. GXT solves this by adding a dummy DOM element if getElement is called on the widget before it’s been rendered. The following code shows the important part of the getElement method:
         if (!rendered) {
          if (dummy == null) dummy = DOM.createDiv();
          return dummy;
        }

    The onAttach method then removes this dummy DOM element (which it calls a proxy) and calls the components render method.

  6. The components render method is the work horse of the framework and performs the following :
    • calls beforeRender()
    • Intializes plugins
    • calls createStyles()
    • calls onRender()
    • If events have been added, registers to revieve
    • Adds the base style name
    • calls afterRender()
    • Fires the Events.Render event

    Out of all of these, it’s the onRender method that should be overriden by components. A component onRender method MUST call setElement otherwise on returning from the onRender method an exception will be thrown.

From this it can be seen that GXT makes the rendering process a little simpler by only requiring a component to override onRender. What’s more there are times when you don’t actually know what type of DOM element will represent the component until it’s time to actually render it, the default GWT render process does not support this.

As an example, lets compare the GWT HTML widget with the GXT Html (camel case!) component. The GWT version needs to know the DOM component type up front, simply because setElement MUST be called during widget creation, which means the GWT HTML component is ALWAYS a DIV with the HTML as the innerHtml. GXT however allows components to defer the decision on the underlying DOM Element until render time and so the GXT Html component allows the actual parent tag type to be set at any time (before rendering) using the setTagName() method. At render time the correct component type is created and rendered.