Friday, April 30, 2010

Sample code for a GWT Popup Anchor that links to an External URL

Do you need to have an anchor on your GWT page that pops up a window that navigates to an external/arbitrary URL? I’m your guy.

I have an easy solution that involves adding a ClickHandler to your anchor. The image below shows the result. After clicking the Redeem Now button (uses my ImageAnchor widget from the previous post), a window pops up and navigates to an external URL.

gwt_popup_external

View.java Sample Code

In your view file, declare your anchor. I use UiBinder so I have the UiField annotation, but you don’t need it if you aren’t using UiBinder.

@UiField
Anchor redeemButton;

Define a JavaScript function in your view:

public static native void popupAnchor(String url) /*-{
    window.open(url, 'Redeem Rewards', 'width=1024,height=900,scrollbars=yes');
    return false;
}-*/;

Create a method that attaches a ClickHandler to your anchor:

private HandlerRegistration updateAnchorClickHandler(Anchor anchor, HandlerRegistration existingClickHandler, final String rewardsURL) {
    // We will be updating the URL from time to time from a Timer
    // Make sure we aren't adding multiple handlers to the same anchor
    if (existingClickHandler != null) {
        existingClickHandler.removeHandler();
    }
    HandlerRegistration newHandler = anchor.addClickHandler(new ClickHandler() {
        public void onClick(ClickEvent event) {
            popupAnchor(rewardsURL);
        }
    });
    return newHandler;
}

Declare a handler registration as a class member variable. This holds on to the ClickHandler’s registration to the anchor. This allows us to remove it in case the popup url needs to be updated.

private HandlerRegistration redeemHandlerRegistration = null;

Finally, whenever you want to assign a new/updated popup URL for the anchor, simply call your method:

String rewardsURL = whatever you want

redeemHandlerRegistration = updateAnchorClickHandler(redeemButton, redeemHandlerRegistration, rewardsURL);

 

 

Technorati Tags: ,

ImageAnchor Sample Code: a GWT Anchor Widget that displays an Image

I needed to create an anchor to an external site in GWT, but display an image in that anchor instead of text. I was surprised this widget wasn’t included in standard set offered by GWT. But it turned out to be an easy thing to implement.

Here’s what it is, as shown in Firebug. It is an anchor that surrounds an image:

gwt_imageanchor

Sample Code

ImageAnchor.java

This class is the implementation of the actual widget. It needs to be in some spot in your project. Note that this implementation assumes you are using the ImageResource facility. You could also provide the image via URL, by adding a setUrl() method to ImageAnchor, and changing the Image() constructor to take a String url.

package com.tendril.ui.components.reward.client.view;

import com.google.gwt.user.client.ui.Image;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.DOM;

public class ImageAnchor extends Anchor {

    public ImageAnchor() {
    }

    public void setResource(ImageResource imageResource) {
        Image img = new Image(imageResource);
        img.setStyleName("navbarimg");
        DOM.insertBefore(getElement(), img.getElement(), DOM
                .getFirstChild(getElement()));
    }
}

UiBinder XML

You don’t have to use UiBinder templating for this. It is optional. But if you are using UiBinder, this is how it goes:

Add the package to your namespaces at the top of the document. I use the rw namespace in my case:

<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
    xmlns:g="urn:import:com.google.gwt.user.client.ui"
    xmlns:rw="urn:import:com.tendril.ui.components.reward.client.view"
    >

Then you can use your widget. For example:

<g:HTMLPanel addStyleNames='{resources.style.redeem_button_div}'>
    <rw:ImageAnchor resource="{resources.redeem_button}"
        ui:field="redeemButton" />
</g:HTMLPanel>

View

You can interact with the widget in your view just like any other Anchor. If fact, for my purposes, I declare it as an Anchor supertype.

@UiField
Anchor redeemButton;

Technorati Tags:

Monday, April 19, 2010

Eclipse hangs in m2eclipse DefaultWagonManager.getRemoteFile

This isn’t a constructive post – I am going to vent about yet another reason I feel the combination of Maven-Subversion-Eclipse-AspectJ is the Bermuda triangle (er, make that square) of Java development.

I hit a hang tonight in Eclipse that comes from m2eclipse. I have seen this before, am irritated and I just want to vent about it.

Our toolset:

  • Eclipse 3.5
  • AspectJ Dev Tools 2.0.2
  • m2eclipse .10.0.2010
  • Subclipse 1.6.10

We have many modules. When I work against trunk, I almost always set Maven to offline mode after doing a full build. I don’t need to be on the tip for what I do.

The reason I evoke Bermuda when referring to this combination is the general unreliability I have when working. Eclipse arbitrarily rebuilds entire projects with a single line of Java changed. AspectJ fails to weave. Eclipse hangs for minutes at a time. On and on. This post is about one cause of the hang issue.

Annoying Hangs in Eclipse

I sporadically get hung up on calls to the Maven repo or Subversion. Eclipse will hang for minutes. I have started to monitor the stack traces, and they are so far they are m2eclipse or subclipse related.

As a good open source citizen, I should really stop what I am doing for half a day when this happens to try and figure out what is going wrong. Better yet, see if anyone else has had the problem and already reported it.

After tonight’s 5 minute hang, I did a search. I found other people with the problem (from 2008), yet no answer.

"Worker-9" prio=10 tid=0x0ab96000 nid=0xdf7 in Object.wait() [0x5eacd000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0xaffea3e8> (a org.apache.maven.wagon.providers.http.JettyClientHttpWagon$WagonExchange)
    at java.lang.Object.wait(Object.java:485)
    at org.eclipse.jetty.client.HttpExchange.waitForDone(HttpExchange.java:134)
    - locked <0xaffea3e8> (a org.apache.maven.wagon.providers.http.JettyClientHttpWagon$WagonExchange)
    at org.apache.maven.wagon.providers.http.JettyClientHttpWagon.sendAndWait(JettyClientHttpWagon.java:245)
    at org.apache.maven.wagon.providers.http.JettyClientHttpWagon.getIfNewer(JettyClientHttpWagon.java:347)
    at org.apache.maven.wagon.providers.http.JettyClientHttpWagon.getIfNewer(JettyClientHttpWagon.java:302)
    at org.apache.maven.repository.legacy.DefaultWagonManager.getRemoteFile(DefaultWagonManager.java:292)
    at org.apache.maven.repository.legacy.DefaultWagonManager.getArtifact(DefaultWagonManager.java:99)
    at org.apache.maven.artifact.resolver.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:247)
    at org.apache.maven.artifact.resolver.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:507)
    at org.apache.maven.repository.legacy.LegacyRepositorySystem.resolve(LegacyRepositorySystem.java:325)
    at org.apache.maven.project.RepositoryModelResolver.resolveModel(RepositoryModelResolver.java:171)
    at org.apache.maven.model.building.DefaultModelBuilder.readParentExternally(DefaultModelBuilder.java:582)
    at org.apache.maven.model.building.DefaultModelBuilder.readParent(DefaultModelBuilder.java:449)
    at org.apache.maven.model.building.DefaultModelBuilder.build(DefaultModelBuilder.java:182)
    at org.apache.maven.model.building.DefaultModelBuilder.build(DefaultModelBuilder.java:117)
    at org.apache.maven.project.DefaultProjectBuilder.build(DefaultProjectBuilder.java:117)
    at org.apache.maven.project.DefaultProjectBuilder.build(DefaultProjectBuilder.java:81)
    at org.maven.ide.eclipse.internal.embedder.MavenImpl.readProject(MavenImpl.java:418)
    at org.maven.ide.eclipse.internal.project.MavenProjectManagerImpl$Refresher.phaseOne(MavenProjectManagerImpl.java:448)
    at org.maven.ide.eclipse.internal.project.MavenProjectManagerImpl.refresh(MavenProjectManagerImpl.java:368)
    at org.maven.ide.eclipse.internal.project.MavenProjectManagerRefreshJob.run(MavenProjectManagerRefreshJob.java:93)
    at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)

What am I going to do about it?

I know what I should do. Every time I hit an annoying problem, I should drop what I am doing and try and debug it.

I tried debugging the AspectJ issue, and gave up after a lot of problems getting a working debug environment with matching source files for everything. So I would like to help debug this one, but I just don’t have the desire to fight that again.

There is an easy workaround. I was not on my corporate VPN when this happened. I have only seen this problem when off the VPN. Therefore, I can just log into VPN all the time and the problem is avoided.

But I shouldn’t have to do that. My Maven settings clearly indicate an offline build.

If you are on this page, you must be having this same problem (I don’t have subscribers to this blog). Let me know with a comment. If others are annoyed maybe I will devote some time to debugging.

Technorati Tags: ,

Friday, April 16, 2010

Creating a GWT Popup Window – Sample Code Example for PopupPanel and UiBinder

This post is an easy tutorial for creating a popup window in GWT using the PopupPanel component included in the panel. Its really quite simple, so hopefully it will get you going in just a few minutes.

This screenshot shows what is accomplished in this tutorial:

gwt_popup

This example was built using GWT SDK 2.0.3. It employs the UiBinder templating facility to define the contents of the popup, but you can easily do without UiBinder as well.

Sample Code

Because I am lazy, I am splatting in my code “as is”. This means you need to understand that my popup window is called EEGraphPopup and my main application window is the RewardsView. Otherwise, it should all be self explanatory.

EEGraphPopup.java

Create a new Java file in your client directory. This file holds the code behind your popup panel. Notice it directly extends PopupPanel.

package com.tendril.ui.components.reward.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiTemplate;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.Widget;

/**
* A simple popup that displays a EEGraph's information.
*/
public class EEGraphPopup extends PopupPanel {

    @UiTemplate("EEGraphPopup.ui.xml")
    interface Binder extends UiBinder<Widget, EEGraphPopup> { }
    private static final Binder binder = GWT.create(Binder.class);
    public EEGraphPopup() {
      // The popup's constructor's argument is a boolean specifying that it
      // auto-close itself when the user clicks outside of it.
      super(true);
      add(binder.createAndBindUi(this));
    }
}

EEGraphPopup.ui.xml

If you are using UiBinder to define your popup view, create this file in your client directory.

<ui:UiBinder
  xmlns:ui='urn:ui:com.google.gwt.uibinder'
  xmlns:g='urn:import:com.google.gwt.user.client.ui'
>

  <ui:image field='ee_graph' src='consumer_ee_graph.png'/>

  <ui:style>

  @sprite .ee_graph {
    gwt-image: 'ee_graph';
    display: block;
    margin-left: auto;
    margin-right: auto;
  }

  </ui:style>

  <g:HTMLPanel styleName='ee_graph_popup'>
      <span>Baseline Energy Usage</span>
    <div class='{style.ee_graph}'/>
  </g:HTMLPanel>

</ui:UiBinder>

rewards.css

Put this stuff in your application’s CSS file.

.ee_graph_popup {
    background: #dfefc8;
    border: 1px solid #808080;
    padding: 0.5em;
    width: 650px;
    height: 400px;
}

RewardsView.java

This code belongs in the view that triggers the popup. I trigger mine via a button ClickHandler. Notice how the line that centers your popup. Also, setGlassEnabled dims the rest of the screen – a very nice feature!

public void onClick(ClickEvent event) {
    EEGraphPopup popup = new EEGraphPopup();
    popup.setGlassEnabled(true);
    popup.center();
    popup.show();
}

References

This post was made possible by a couple other blog posts. Check in with these too:

Technorati Tags: ,

Thursday, April 15, 2010

Sample code for GWT TabLayoutPanel - overriding the default CSS styles

If you are lucky like me, you have a designer who creates your screen mockups for you. This is great, because I suck at creating roundy-border type stuff that actually looks good on a web page. Its all great, until you have to figure out how to build the stuff they design.

This post is about styling a GWT TabLayoutPanel in a way that will make your designer friend happy. Well, as much as one of those guys can ever  be happy.

Here is what I have built. Notice how the tabs are styled – much better than the default styles you get out of the box.

gwt_tabcontrol_css_styled

This sample uses the GWT SDK 2.03. It employs UiBinder, but this technique can be used without it as well.

Approach – Build a Custom Theme

There are references out there that indicate that you may be override the default GWT styles in your own custom CSS stylesheet. They seem to indicate that this will take precedence over the styles defined by the CSS in the standard theme.

I never got that to work, as I could see in Firebug that the theme CSS files were loading later than my custom CSS file. No matter how I rearranged in the includes in my HTML file.

So I took a different tack – I created a custom theme based off of a standard theme. Upon creating the custom theme, I changed the default styles for tab controls. This approach was both easy and effective. Note that it won’t work well for cases in which you have multiple tab controls in your project and need to style them differently. You will need to something with adding styles – details for which I don’t have.

For reference, you can find some links out there on creating custom themes. I used the official GWT docs for this, and they were good:

Sample Code

The code below shows the different snippets required to make this happen.

Theme CSS

I will not include everything you need here, as you will use a standard theme CSS as your base for working. Do a search in the SDK to find the base theme you want – standard.css, dark.css, or chrome.css. For Eclipse users, the SDK is found in a location such as:

eclipse/plugins/com.google.gwt.eclipse.sdkbundle.2.0.3/gwt-2.0.3

Once you find your base CSS, copy it into your war directory in your project. Open the file, and search for the Tab styles. Beyond this, it is an exercise in CSS and Firebug to get your tabs looking exactly how you need. For me, mine are defined like this:

.gwt-TabLayoutPanel
{
    height: 300px;
}

.gwt-TabLayoutPanel .gwt-TabLayoutPanelTabs {
}
.gwt-TabLayoutPanel .gwt-TabLayoutPanelContent {
  border-color: #e6e7e8;
  border-style: solid;
  border-width: 3px 2px 2px;
  overflow: hidden;
  padding: 6px;
  background: #FFFFFF; 
}
.gwt-TabLayoutPanel .gwt-TabLayoutPanelTab {
  margin-left: 6px;
  padding: 3px 8px 3px 8px;
  cursor: pointer;
  cursor: hand;
  color: black;
  font-size: 1.2em;
  color: #8bc53d;
  text-align: center;
  background: #458818;
}
.gwt-TabLayoutPanel .gwt-TabLayoutPanelTab-selected {
  cursor: default;
  background: #8bc53d;
  font-size: 1.2em;
  color: #FFFFFF;
}

Configure Theme in Rewards.gwt.xml File

Find your *.gwt.xml file, usually in the top level directory of your packages. In here, you will need to disable any standard theme you are using, and inherit the basic CSS style objects into your project. Check the reference in the GWT docs listed above for more info.

<!--  <inherits name='com.google.gwt.user.theme.standard.Standard'/>-->
<!--  <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
<!--  <inherits name='com.google.gwt.user.theme.dark.Dark'/>     -->
<inherits name='com.google.gwt.user.theme.standard.StandardResources'/>   

Include Custom Theme in Rewards.html

Next, add in your theme’s css file into your UI by including it in the host page. Your html file will be in your war directory. Update it to include your custom .css file, like:

<link type="text/css" rel="stylesheet" href="rewards.css">
<link type="text/css" rel="stylesheet" href="tendril_theme.css">

UiBinder Page

The next thing to do is actually define your TabLayoutPanel in your UI. I use UiBinder for this, but you can do this programmatically as well. Notice that I don’t declare style info for the tab widgets – they automatically consume the custom theme styles.

<g:TabLayoutPanel ui:field="programsTabPanel" barHeight="2" barUnit="EM">
    <g:tab>
        <g:header>Available</g:header>
        <g:HorizontalPanel styleName='program_tab'>
            <g:cell width="35%">
                    CONTENT GOES HERE 
            </g:cell>
            <g:cell width='65%'>
                    CONTENT GOES HERE 
            </g:cell>
        </g:HorizontalPanel>
    </g:tab>
    <g:tab>
        <g:header>Demand Response</g:header>
        <g:HorizontalPanel>
            <g:cell width="35%">
                    CONTENT GOES HERE 
            </g:cell>
            <g:cell width='65%'>
                    CONTENT GOES HERE 
            </g:cell>
        </g:HorizontalPanel>
    </g:tab>
    <g:tab>
        <g:header>Energy Efficiency</g:header>
        <g:HorizontalPanel styleName='program_tab'>
            <g:cell width="35%">
                    CONTENT GOES HERE 
            </g:cell>
            <g:cell width='65%'>
                   CONTENT GOES HERE 
            </g:cell>
        </g:HorizontalPanel>
    </g:tab>
</g:TabLayoutPanel>

Now, the next time you refresh the browser your tabs should look pretty.

Technorati Tags: ,,,,

Code sample for making GWT TabLayoutPanel tabs visible and invisible

Here are some code snippets for making TabLayoutPanel tabs visible and invisible. I use it to provision all my tabs in a UiBinder template up front, but have only those tabs that are relevant visible. This requires me to immediately make most of the tabs invisible on load, and then triggering their visibility when the user takes certain actions.

Use Case

The initial rendering of the tabs looks like this. (if you want to know how I styled the tabs, see another post of mine) Notice only one tab is visible:

gwt_tabcontrol_initial

After the user clicks on one of the enroll buttons, I make the associated tab visible on the control, which results in this:

gwt_tabcontrol_visible

Sample Code

The following is the sample code that I use to make all of this happen.

UiBinder Page

Here is a snippet from my RewardsView.ui.xml UiBinder file, with most of the user text redacted for brevity. Notice how I define all of the possible tabs up front:

<g:TabLayoutPanel ui:field="programsTabPanel" barHeight="2" barUnit="EM">
    <g:tab>
        <g:header>Available</g:header>
        <g:HorizontalPanel styleName='program_tab'>
            <g:cell width="35%">
                    CONTENT GOES HERE 
            </g:cell>
            <g:cell width='65%'>
                    CONTENT GOES HERE 
            </g:cell>
        </g:HorizontalPanel>
    </g:tab>
    <g:tab>
        <g:header>Demand Response</g:header>
        <g:HorizontalPanel>
            <g:cell width="35%">
                    CONTENT GOES HERE 
            </g:cell>
            <g:cell width='65%'>
                    CONTENT GOES HERE 
            </g:cell>
        </g:HorizontalPanel>
    </g:tab>
    <g:tab>
        <g:header>Energy Efficiency</g:header>
        <g:HorizontalPanel styleName='program_tab'>
            <g:cell width="35%">
                    CONTENT GOES HERE 
            </g:cell>
            <g:cell width='65%'>
                   CONTENT GOES HERE 
            </g:cell>
        </g:HorizontalPanel>
    </g:tab>
</g:TabLayoutPanel>

Hiding a tab during initialization of the UiBinder Composite

I then set most of my tabs to invisible during construction of the UiBinder composite. Notice that I had to introduce an extra getParent() call to do this. If you don’t do this, you will find small slivers of the invisible tabs still visible (and still clickable by the user!). Making the parent invisible properly obscures the whole thing.

@UiField TabLayoutPanel programsTabPanel;

public RewardsView(String firstName) {
    initWidget(uiBinder.createAndBindUi(this));
    programsTabPanel.getTabWidget(1).getParent().setVisible(false);
    programsTabPanel.getTabWidget(2).getParent().setVisible(false);
}

Its a bit lame that I reference the tabs by index, but it works for me.

Displaying a hidden tab in a button ClickHandler

Look at the StockWatcher sample if you need to learn how to create a ClickHandler for a button. You could also trigger visibility of a tab via other means. But in the end, you need a line of code like this to make the tab visible again:

programsTabPanel.getTabWidget(2).getParent().setVisible(true);

You will need to determine the right tab index to enable (I show 2 above), but otherwise its a piece of cake. Done!

Technorati Tags: ,

Friday, April 2, 2010

Solution: Mouse disappears when using Skype Share Desktop in Windows VirtualBox VM on Ubuntu Linux Host

That’s a mouthful. But I have an easy solution to this annoying problem. It happens when I run Skype in a Windows VM, and then opt to share desktop. The mouse will disappear, which makes for a tough time navigating around.

This is my configuration:

  • Host OS: Ubuntu Linux 9.10 (with all updates)
  • Guest OS: Windows XP SP3 (with all updates)
    • Guest additions have been installed
  • Hypervisor: VirtualBox 3.1.4
  • Skype: Windows version 4.2.0.155
  • Hardware: Dell Latitude E6400

Solution

Is simple. When I installed

guest additions, it enabled a feature called “Mouse Integration”. It is enabled by default. However, with Skype it causes this mouse problem.

For the duration of your Skype call, simply disable Mouse Integration and this problem goes away. Do this from the VirtualBox menu bar for your VM:

  • Machine –> Disable Mouse Integration
Technorati Tags: ,,