ActiveLink.java
package com.itmill.toolkit.demo.sampler;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Map;

import com.itmill.toolkit.terminal.PaintException;
import com.itmill.toolkit.terminal.PaintTarget;
import com.itmill.toolkit.terminal.Resource;
import com.itmill.toolkit.ui.Component;
import com.itmill.toolkit.ui.Link;
import com.itmill.toolkit.ui.Button.ClickEvent;
import com.itmill.toolkit.ui.Button.ClickListener;

public class ActiveLink extends Link {

    private static final String TAG = "activelink";

    private static final Method LINK_FOLLOWED_METHOD;

    private HashSet listeners = new HashSet();

    public ActiveLink() {
        super();
    }

    public ActiveLink(String caption, Resource resource, String targetName,
            int width, int height, int border) {
        super(caption, resource, targetName, width, height, border);
    }

    public ActiveLink(String caption, Resource resource) {
        super(caption, resource);
    }

    @Override
    public String getTag() {
        return TAG;
    }

    static {
        try {
            LINK_FOLLOWED_METHOD = LinkActivatedListener.class
                    .getDeclaredMethod("linkActivated",
                            new Class[] { LinkActivatedEvent.class });
        catch (final java.lang.NoSuchMethodException e) {
            // This should never happen
            throw new java.lang.RuntimeException(
                    "Internal error finding methods in ActiveLink");
        }
    }

    /**
     * Adds the link activated listener.
     
     @param listener
     *            the Listener to be added.
     */
    public void addListener(LinkActivatedListener listener) {
        listeners.add(listener);
        addListener(LinkActivatedEvent.class, listener, LINK_FOLLOWED_METHOD);
        if (listeners.size() == 1) {
            requestRepaint();
        }
    }

    /**
     * Removes the link activated listener.
     
     @param listener
     *            the Listener to be removed.
     */
    public void removeListener(ClickListener listener) {
        listeners.remove(listener);
        removeListener(ClickEvent.class, listener, LINK_FOLLOWED_METHOD);
        if (listeners.size() == 0) {
            requestRepaint();
        }
    }

    /**
     * Emits the options change event.
     */
    protected void fireClick(boolean linkOpened) {
        fireEvent(new LinkActivatedEvent(this, linkOpened));
    }

    @Override
    public void paintContent(PaintTarget targetthrows PaintException {
        super.paintContent(target);

        if (listeners.size() 0) {
            target.addVariable(this, "activated"false);
            target.addVariable(this, "opened"false);
        }
    }

    @Override
    public void changeVariables(Object source, Map variables) {
        super.changeVariables(source, variables);
        if (!isReadOnly() && variables.containsKey("activated")) {
            final Boolean activated = (Booleanvariables.get("activated");
            final Boolean opened = (Booleanvariables.get("opened");
            if (activated != null && activated.booleanValue() && !isReadOnly()) {
                fireClick((opened != null && opened.booleanValue() true
                        false));
            }
        }
    }

    public class LinkActivatedEvent extends Component.Event {

        private static final long serialVersionUID = -6406243194818230362L;

        private boolean linkOpened;

        /**
         * New instance of text change event.
         
         @param source
         *            the Source of the event.
         */
        public LinkActivatedEvent(Component source, boolean linkOpened) {
            super(source);
            this.linkOpened = linkOpened;
        }

        /**
         * Gets the ActiveLink where the event occurred.
         
         @return the Source of the event.
         */
        public ActiveLink getActiveLink() {
            return (ActiveLinkgetSource();
        }

        /**
         * Indicates whether or not the link was opened on the client, i.e in a
         * new window/tab. If the link was not opened, the listener should react
         * to the event and "do something", otherwise the link does nothing.
         
         @return true if the link was opened on the client
         */
        public boolean isLinkOpened() {
            return linkOpened;
        }
    }

    /**
     * ActiveLink click listener
     */
    public interface LinkActivatedListener {

        /**
         * ActiveLink has been activated.
         
         @param event
         *            ActiveLink click event.
         */
        public void linkActivated(LinkActivatedEvent event);

    }

}