package com.vaadin.demo.sampler; import java.io.Serializable; import java.lang.reflect.Method; import java.util.HashSet; import java.util.Map; import com.vaadin.demo.sampler.gwt.widgetset.client.ui.VActiveLink; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Resource; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.ClientWidget; import com.vaadin.ui.Component; import com.vaadin.ui.Link; @SuppressWarnings("serial") @ClientWidget(VActiveLink.class) public class ActiveLink extends Link { private static final Method LINK_FOLLOWED_METHOD; private HashSet<LinkActivatedListener> listeners = new HashSet<LinkActivatedListener>(); 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); } static { try { LINK_FOLLOWED_METHOD = LinkActivatedListener.class .getDeclaredMethod("linkActivated", new Class[] { LinkActivatedEvent.class }); } catch (final NoSuchMethodException e) { // This should never happen throw new 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(LinkActivatedListener 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 target) throws 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<String, Object> variables) { super.changeVariables(source, variables); if (!isReadOnly() && variables.containsKey("activated")) { final Boolean activated = (Boolean) variables.get("activated"); final Boolean opened = (Boolean) variables.get("opened"); if (activated != null && activated.booleanValue() && !isReadOnly()) { fireClick((opened != null && opened.booleanValue() ? true : false)); } } } public class LinkActivatedEvent extends Component.Event { 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 (ActiveLink) getSource(); } /** * 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 extends Serializable { /** * ActiveLink has been activated. * * @param event * ActiveLink click event. */ public void linkActivated(LinkActivatedEvent event); } }