Thursday, August 22, 2013

Re: ImageResource question

Beware when implementing com.google.gwt.resources interfaces (whose implementations are expected to be generated) that they might change and break your code. GWT 2.6 will introduce a new isStandalone() method for instance.

Also, BTW, you should probably use UriUtils.unsafeCastFromUntrustedString; it works exactly the same as fromSafeConstants, it's just a matter of "semantics": one says it's "safe" when the other clearly states that it's "unsafe but necessary".

On Wednesday, August 21, 2013 7:45:04 PM UTC+2, Steve C wrote:
I haven't sorted out in my mind the best approach for a few of the details, in particular making it reusable, but this works.  Consider it more of a "proof of concept".

You'd need to create red.png in the war directory, or could try out a data url (which per my tests works with this).

For a bundle with more images, the asynchronicity gets to be a bigger issue, since you'd need to have something like a "master" callback once all of the individual image callbacks have completed.  Also, there's no facility for sprites, although I think it could be implemented.


public class DynamicResourcesDemo implements EntryPoint {
   
    private DynamicMenuBarResources resources;
    private MenuBar bar;

    public void onModuleLoad() {
       
        MenuBar.Resources defaultResources = GWT.create(MenuBar.Resources.class);
        MyImageResource imgres = new MyImageResource(defaultResources.menuBarSubMenuIcon());
        resources = new DynamicMenuBarResources(imgres);
       
        imgres.load("red.png", new Callback<Void, Throwable>() {
            @Override
            public void onSuccess(Void result) {
                showUi();
            }
           
            @Override
            public void onFailure(Throwable reason) {
                Window.alert("Error");
            }
        });
    }
   
    private void showUi() {
        MenuBar fileMenu = new MenuBar(true);
        fileMenu.addItem("Open", new Scheduler.ScheduledCommand() {
            @Override
            public void execute() {
                Window.alert("Open File");
            }
        });
        fileMenu.addItem("Exit", new Scheduler.ScheduledCommand() {
            @Override
            public void execute() {
                Window.alert("So long!");
            }
        });
        MenuBar actionsMenu = new MenuBar(true, resources);
        actionsMenu.addItem("File", fileMenu);
        bar = new MenuBar();
        bar.addItem("Actions", actionsMenu);
       
        RootPanel.get().add(bar);
    }
}

//-------------------------------------------------------------

public class DynamicMenuBarResources implements Resources {
   
    private static Resources base = GWT.create(Resources.class);
    private ImageResource menuBarSubmenuIconResource;

    public DynamicMenuBarResources() {
    }

    public DynamicMenuBarResources(ImageResource menuBarSubmenuIconResource) {
        this.menuBarSubmenuIconResource = menuBarSubmenuIconResource;
    }

    @Override
    @ImageOptions(flipRtl = true)
    public ImageResource menuBarSubMenuIcon() {
        if (menuBarSubmenuIconResource != null) {
            return menuBarSubmenuIconResource;
        } else {
            return base.menuBarSubMenuIcon();
        }
    }

}

//----------------------------------------------------

public class MyImageResource implements ImageResource {
   
    private Image image;
    private ImageResource defaultResource;
    private boolean imageValid = false;
   
    public MyImageResource(ImageResource defaultResource) {
        image = new Image();
        this.defaultResource = defaultResource;
    }

    public void load(String url, final Callback<Void, Throwable> callback) {
        image.setUrl(url);
        final Panel pnl = new SimplePanel();
        pnl.add(image);
        Style pnlStyle = pnl.getElement().getStyle();
        pnlStyle.setVisibility(Visibility.HIDDEN);
        pnlStyle.setPosition(Position.ABSOLUTE);
        image.addLoadHandler(new LoadHandler() {
            @Override
            public void onLoad(LoadEvent event) {
                RootPanel.get().remove(pnl);
                imageValid = true;
                if (callback != null) callback.onSuccess(null);
            }
        });
        image.addErrorHandler(new ErrorHandler() {
            @Override
            public void onError(ErrorEvent event) {
                RootPanel.get().remove(pnl);
                // this lets the resource fall back to the default
                if (callback != null) callback.onSuccess(null);
                // this would instead invoke the error handling for the callback
                //if (callback != null) callback.onFailure(new Exception("Image Resource Load Error"));
            }
        });
        RootPanel.get().add(pnl);
    }

    @Override
    public String getName() {
        return imageValid ? "" : defaultResource.getName();  // ???
    }

    @Override
    public int getHeight() {
        return imageValid ? image.getHeight() : defaultResource.getHeight();
    }

    @Override
    public int getLeft() {
        return imageValid ? 0 : defaultResource.getLeft();
    }

    @Override
    public SafeUri getSafeUri() {
        return imageValid ? UriUtils.fromSafeConstant(image.getUrl()) : defaultResource.getSafeUri();
    }

    @Override
    public int getTop() {
        return imageValid ? 0 : defaultResource.getTop();
    }

    @Override
    @Deprecated
    public String getURL() {
        return imageValid ? image.getUrl() : defaultResource.getURL();
    }

    @Override
    public int getWidth() {
        return imageValid ? image.getWidth() : defaultResource.getWidth();
    }

    @Override
    public boolean isAnimated() {
        return imageValid ? false : defaultResource.isAnimated();  // ???
    }

}


On Saturday, August 17, 2013 12:30:11 PM UTC-4, df wrote:
Could you give some code?
Thanks

W dniu czwartek, 15 sierpnia 2013 01:05:30 UTC+2 użytkownik Steve C napisał:
Thanks for asking that question - it led me to a solution to a problem that I've had, which is "skinning" an app using different versions of resources loaded asynchronously from the war directory as opposed to coded into a ClientBundle.

I created a client bundle extending SimplePager.Resources, with sources that reference dummy placeholder images in my source tree, then created a separate class implementing that interface.  In the constructor I populate it from the GWT.created bundle (since some of the resources aren't dynamic, and I can just delegate through to them) but then load my dynamic images into Image widgets. Those, in turn, are each given to an implementation of ImageResource that holds an Image widget, and obtains the width, height, url, etc. from it (wasn't sure what the heck to do with getName, or how to implement isAnimated). Those are the return values from the associated methods in my resource object.  And then I give that to the pager constructor.

The asychronicity turned out to be a bear, since I'm using a LoadHandler for each image to know when the size values will be available, and that won't do anything unless I actually add the Image to the document, so I had to create a hidden div to put them into. I haven't yet tested if that's necessary with a data: url. And a lot of layout tasks had to be pushed off into a callback.

The concept works, but I suspect that unless I make all versions of a particular image the same size, I can't use any CssResource tricks based on the image. That's probably not a big deal - since the variations generally would all be the same size.  Also, I don't think that there's any existing Resource class in the API with CSS resources that depend on the images, so it would only be an issue with custom resource classes.

On Wednesday, August 14, 2013 3:42:34 AM UTC-4, df wrote:
Hello. Is There any way to create ImageResource dynamically? For example : I get images from WebService in base64 format and I don't have opportunity to have all images on the server at compile time. Can i cast Images to ImageResource? Or is there any other solution?
Thanks for help.

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscribe@googlegroups.com.
To post to this group, send email to google-web-toolkit@googlegroups.com.
Visit this group at http://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/groups/opt_out.

No comments:

Post a Comment