GWT - Update the CSS images to be used with the ClientBundles

GWT 2.0 simplified the managing of the resources in bundles (images, CSS, strings). For this the main 'actor' is the interface ClientBundle, which can be extended and populated with function definitions.

For example if we have the module com.mycompany.module1 then we can add a new package to the client code com.mycompany.module1.client.resources where we'll put our image resources.

Here we need to add our "bundle descriptor" Java interface, and copy the images (*.gif, *.png) under it. The link between the image file and the function is done through an annotation Source. So far nothing new. The point that I want to emphasise is what we do we our code that uses in lots of places the image key strings or image CSS classes (i.e. button.setIconsStyle("ICON-add")) ?

One solution is to replace everywhere the CSS references of the images with the call of the "bundle descriptor" interface, and another solution will be to build some helpers that will do the this "resources translation" for us, and the old code remains unchanged. The later I will present here:


public interface MyImagesBundle extends ClientBundle {

   /* create an instance of images bundle - static public one */
   MyImagesBundle INSTANCE = GWT.create(MyImagesBundle.class);

   /* add the definition of the icons */

   @Source ("add.png")
   ImageResource addIcon();

   @Source ("del.png")
   ImageResource delIcon();

}


This is nice here, but the some controls may not use directly the ImageResource class, but the AbstractImagePrototype, so we need the helper class to translate the "strings" to the "AbstractImagePrototype". And for this we'll add a nested static class to out bundle descriptor interface "MyImagesBundle", so we have the next code sample:

public interface MyImagesBundle extends ClientBundle {
   MyImagesBundle INSTANCE = GWT.create (MyImagesBundle.class);

   public static class Util {

      /* mapping of the CSS icon classes and the image resources */
      private static HashMap<String, ImageResource> ICONS = 
           new HashMap<String, ImageResource> ();

      /* here we build the mapping */
      static  {
          add ("ICON-add", INSTANCE.addIcon ());
          add ("ICON-del", INSTANCE.delIcon ());
      }

      /* conversion function */
      public static AbstractImagePrototype get (String imageCls) {
         ImageResource ir = ICONS.get (imageCls);
         if (ir != null)
            return AbstractImagePrototype.create (ir);
         return null;
      }

      /* adding helper function */
      protected static void add (String imageCls, ImageResource ir) {
         ICONS.put (imageCls, ir);
      }
     
   }

   @Source ("add.png")
   ImageResource addIcon ();

   @Source ("del.png")
   ImageResource delIcon ();
}

The calls of the resources can be done like here:

Button b = ...
b.setImage (MyImagesBundle.Util.get ("ICON-add"));

or

Button b = ...
b.setImage(AbstractImagePrototype.create(MyImagesBundle.INSTANCE.addIcon()));

If we need to have more bundles, we can use the above Util class as a base for the subclassed ones, like in the below sample:

public interface MySecondBundle extends ClientBundle {
    MySecondBundle INSTANCE = GWT.create (MySecondBundle.class);

    public static class Util extends MyImagesBundle.Util {
        /* here we just add the new mappings */
        static {
           add ("ICON-import", INSTANCE.importIcon();
           ...
        }
    }

    @Source ("import.gif")
    ImageResource importIcon ();
}

so the second bundle is much simpler, and it can "override" the icons with the same "icon css class", which can be good or bad. But either way goes, we still have the possibility to chose the right icon through the INSTANCE variable:

MyScondBundle.Util.get ("ICON-import");
MySecondBundle.INSTANCE.importIcon();
MyImagesBundle.INSTANCE.addIcon();
MyImagesBundle.Util.get ("ICON-add");

Cheers!

No comments:

Post a Comment