diff options
author | Teemu Suo-Anttila <teemusa@vaadin.com> | 2016-03-10 22:40:51 +0200 |
---|---|---|
committer | Teemu Suo-Anttila <teemusa@vaadin.com> | 2016-03-14 07:59:12 +0200 |
commit | a6653d3fe49e6a97468ac09f7f2f4d621bea1078 (patch) | |
tree | 96c82e20ca6551ee4c14c8877f0258b25c63cddf /server/src/main/java/com/vaadin/ui/Button.java | |
parent | f7e57d77ce621ee39167369c31d989edc5633266 (diff) | |
download | vaadin-framework-a6653d3fe49e6a97468ac09f7f2f4d621bea1078.tar.gz vaadin-framework-a6653d3fe49e6a97468ac09f7f2f4d621bea1078.zip |
Migrate vaadin-server build to maven
Change-Id: I5c740f4e9cb28103bab199f9a552153d82277e7e
Diffstat (limited to 'server/src/main/java/com/vaadin/ui/Button.java')
-rw-r--r-- | server/src/main/java/com/vaadin/ui/Button.java | 654 |
1 files changed, 654 insertions, 0 deletions
diff --git a/server/src/main/java/com/vaadin/ui/Button.java b/server/src/main/java/com/vaadin/ui/Button.java new file mode 100644 index 0000000000..677e8cac7d --- /dev/null +++ b/server/src/main/java/com/vaadin/ui/Button.java @@ -0,0 +1,654 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.ui; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.util.Collection; + +import org.jsoup.nodes.Attributes; +import org.jsoup.nodes.Element; + +import com.vaadin.event.Action; +import com.vaadin.event.ShortcutAction; +import com.vaadin.event.ShortcutAction.KeyCode; +import com.vaadin.event.ShortcutAction.ModifierKey; +import com.vaadin.event.ShortcutListener; +import com.vaadin.server.Resource; +import com.vaadin.shared.MouseEventDetails; +import com.vaadin.shared.ui.button.ButtonServerRpc; +import com.vaadin.shared.ui.button.ButtonState; +import com.vaadin.ui.declarative.DesignAttributeHandler; +import com.vaadin.ui.declarative.DesignContext; +import com.vaadin.ui.declarative.DesignFormatter; +import com.vaadin.util.ReflectTools; + +/** + * A generic button component. + * + * @author Vaadin Ltd. + * @since 3.0 + */ +@SuppressWarnings("serial") +public class Button extends AbstractFocusable implements + Action.ShortcutNotifier { + + private ButtonServerRpc rpc = new ButtonServerRpc() { + + @Override + public void click(MouseEventDetails mouseEventDetails) { + fireClick(mouseEventDetails); + } + + @Override + public void disableOnClick() throws RuntimeException { + setEnabled(false); + // Makes sure the enabled=false state is noticed at once - otherwise + // a following setEnabled(true) call might have no effect. see + // ticket #10030 + getUI().getConnectorTracker().getDiffState(Button.this) + .put("enabled", false); + } + }; + + /** + * Creates a new push button. + */ + public Button() { + registerRpc(rpc); + } + + /** + * Creates a new push button with the given caption. + * + * @param caption + * the Button caption. + */ + public Button(String caption) { + this(); + setCaption(caption); + } + + /** + * Creates a new push button with the given icon. + * + * @param icon + * the icon + */ + public Button(Resource icon) { + this(); + setIcon(icon); + } + + /** + * Creates a new push button with the given caption and icon. + * + * @param caption + * the caption + * @param icon + * the icon + */ + public Button(String caption, Resource icon) { + this(); + setCaption(caption); + setIcon(icon); + } + + /** + * Creates a new push button with a click listener. + * + * @param caption + * the Button caption. + * @param listener + * the Button click listener. + */ + public Button(String caption, ClickListener listener) { + this(caption); + addListener(listener); + } + + /** + * Click event. This event is thrown, when the button is clicked. + * + * @author Vaadin Ltd. + * @since 3.0 + */ + public static class ClickEvent extends Component.Event { + + private final MouseEventDetails details; + + /** + * New instance of text change event. + * + * @param source + * the Source of the event. + */ + public ClickEvent(Component source) { + super(source); + details = null; + } + + /** + * Constructor with mouse details + * + * @param source + * The source where the click took place + * @param details + * Details about the mouse click + */ + public ClickEvent(Component source, MouseEventDetails details) { + super(source); + this.details = details; + } + + /** + * Gets the Button where the event occurred. + * + * @return the Source of the event. + */ + public Button getButton() { + return (Button) getSource(); + } + + /** + * Returns the mouse position (x coordinate) when the click took place. + * The position is relative to the browser client area. + * + * @return The mouse cursor x position or -1 if unknown + */ + public int getClientX() { + if (null != details) { + return details.getClientX(); + } else { + return -1; + } + } + + /** + * Returns the mouse position (y coordinate) when the click took place. + * The position is relative to the browser client area. + * + * @return The mouse cursor y position or -1 if unknown + */ + public int getClientY() { + if (null != details) { + return details.getClientY(); + } else { + return -1; + } + } + + /** + * Returns the relative mouse position (x coordinate) when the click + * took place. The position is relative to the clicked component. + * + * @return The mouse cursor x position relative to the clicked layout + * component or -1 if no x coordinate available + */ + public int getRelativeX() { + if (null != details) { + return details.getRelativeX(); + } else { + return -1; + } + } + + /** + * Returns the relative mouse position (y coordinate) when the click + * took place. The position is relative to the clicked component. + * + * @return The mouse cursor y position relative to the clicked layout + * component or -1 if no y coordinate available + */ + public int getRelativeY() { + if (null != details) { + return details.getRelativeY(); + } else { + return -1; + } + } + + /** + * Checks if the Alt key was down when the mouse event took place. + * + * @return true if Alt was down when the event occured, false otherwise + * or if unknown + */ + public boolean isAltKey() { + if (null != details) { + return details.isAltKey(); + } else { + return false; + } + } + + /** + * Checks if the Ctrl key was down when the mouse event took place. + * + * @return true if Ctrl was pressed when the event occured, false + * otherwise or if unknown + */ + public boolean isCtrlKey() { + if (null != details) { + return details.isCtrlKey(); + } else { + return false; + } + } + + /** + * Checks if the Meta key was down when the mouse event took place. + * + * @return true if Meta was pressed when the event occured, false + * otherwise or if unknown + */ + public boolean isMetaKey() { + if (null != details) { + return details.isMetaKey(); + } else { + return false; + } + } + + /** + * Checks if the Shift key was down when the mouse event took place. + * + * @return true if Shift was pressed when the event occured, false + * otherwise or if unknown + */ + public boolean isShiftKey() { + if (null != details) { + return details.isShiftKey(); + } else { + return false; + } + } + } + + /** + * Interface for listening for a {@link ClickEvent} fired by a + * {@link Component}. + * + * @author Vaadin Ltd. + * @since 3.0 + */ + public interface ClickListener extends Serializable { + + public static final Method BUTTON_CLICK_METHOD = ReflectTools + .findMethod(ClickListener.class, "buttonClick", + ClickEvent.class); + + /** + * Called when a {@link Button} has been clicked. A reference to the + * button is given by {@link ClickEvent#getButton()}. + * + * @param event + * An event containing information about the click. + */ + public void buttonClick(ClickEvent event); + + } + + /** + * Adds the button click listener. + * + * @param listener + * the Listener to be added. + */ + public void addClickListener(ClickListener listener) { + addListener(ClickEvent.class, listener, + ClickListener.BUTTON_CLICK_METHOD); + } + + /** + * @deprecated As of 7.0, replaced by + * {@link #addClickListener(ClickListener)} + **/ + @Deprecated + public void addListener(ClickListener listener) { + addClickListener(listener); + } + + /** + * Removes the button click listener. + * + * @param listener + * the Listener to be removed. + */ + public void removeClickListener(ClickListener listener) { + removeListener(ClickEvent.class, listener, + ClickListener.BUTTON_CLICK_METHOD); + } + + /** + * @deprecated As of 7.0, replaced by + * {@link #removeClickListener(ClickListener)} + **/ + @Deprecated + public void removeListener(ClickListener listener) { + removeClickListener(listener); + } + + /** + * Simulates a button click, notifying all server-side listeners. + * + * No action is taken is the button is disabled. + */ + public void click() { + if (isEnabled() && !isReadOnly()) { + fireClick(); + } + } + + /** + * Fires a click event to all listeners without any event details. + * + * In subclasses, override {@link #fireClick(MouseEventDetails)} instead of + * this method. + */ + protected void fireClick() { + fireEvent(new Button.ClickEvent(this)); + } + + /** + * Fires a click event to all listeners. + * + * @param details + * MouseEventDetails from which keyboard modifiers and other + * information about the mouse click can be obtained. If the + * button was clicked by a keyboard event, some of the fields may + * be empty/undefined. + */ + protected void fireClick(MouseEventDetails details) { + fireEvent(new Button.ClickEvent(this, details)); + } + + /* + * Actions + */ + + protected ClickShortcut clickShortcut; + + /** + * Makes it possible to invoke a click on this button by pressing the given + * {@link KeyCode} and (optional) {@link ModifierKey}s.<br/> + * The shortcut is global (bound to the containing Window). + * + * @param keyCode + * the keycode for invoking the shortcut + * @param modifiers + * the (optional) modifiers for invoking the shortcut, null for + * none + */ + public void setClickShortcut(int keyCode, int... modifiers) { + if (clickShortcut != null) { + removeShortcutListener(clickShortcut); + } + clickShortcut = new ClickShortcut(this, keyCode, modifiers); + addShortcutListener(clickShortcut); + getState().clickShortcutKeyCode = clickShortcut.getKeyCode(); + } + + /** + * Removes the keyboard shortcut previously set with + * {@link #setClickShortcut(int, int...)}. + */ + public void removeClickShortcut() { + if (clickShortcut != null) { + removeShortcutListener(clickShortcut); + clickShortcut = null; + getState().clickShortcutKeyCode = 0; + } + } + + /** + * A {@link ShortcutListener} specifically made to define a keyboard + * shortcut that invokes a click on the given button. + * + */ + public static class ClickShortcut extends ShortcutListener { + protected Button button; + + /** + * Creates a keyboard shortcut for clicking the given button using the + * shorthand notation defined in {@link ShortcutAction}. + * + * @param button + * to be clicked when the shortcut is invoked + * @param shorthandCaption + * the caption with shortcut keycode and modifiers indicated + */ + public ClickShortcut(Button button, String shorthandCaption) { + super(shorthandCaption); + this.button = button; + } + + /** + * Creates a keyboard shortcut for clicking the given button using the + * given {@link KeyCode} and {@link ModifierKey}s. + * + * @param button + * to be clicked when the shortcut is invoked + * @param keyCode + * KeyCode to react to + * @param modifiers + * optional modifiers for shortcut + */ + public ClickShortcut(Button button, int keyCode, int... modifiers) { + super(null, keyCode, modifiers); + this.button = button; + } + + /** + * Creates a keyboard shortcut for clicking the given button using the + * given {@link KeyCode}. + * + * @param button + * to be clicked when the shortcut is invoked + * @param keyCode + * KeyCode to react to + */ + public ClickShortcut(Button button, int keyCode) { + this(button, keyCode, null); + } + + @Override + public void handleAction(Object sender, Object target) { + button.click(); + } + } + + /** + * Determines if a button is automatically disabled when clicked. See + * {@link #setDisableOnClick(boolean)} for details. + * + * @return true if the button is disabled when clicked, false otherwise + */ + public boolean isDisableOnClick() { + return getState(false).disableOnClick; + } + + /** + * Determines if a button is automatically disabled when clicked. If this is + * set to true the button will be automatically disabled when clicked, + * typically to prevent (accidental) extra clicks on a button. + * <p> + * Note that this is only used when the click comes from the user, not when + * calling {@link #click()} method programmatically. Also, if developer + * wants to re-enable the button, it needs to be done programmatically. + * </p> + * + * @param disableOnClick + * true to disable button when it is clicked, false otherwise + */ + public void setDisableOnClick(boolean disableOnClick) { + getState().disableOnClick = disableOnClick; + } + + @Override + protected ButtonState getState() { + return (ButtonState) super.getState(); + } + + @Override + protected ButtonState getState(boolean markAsDirty) { + return (ButtonState) super.getState(markAsDirty); + } + + /** + * Sets the component's icon and alt text. + * + * An alt text is shown when an image could not be loaded, and read by + * assisitve devices. + * + * @param icon + * the icon to be shown with the component's caption. + * @param iconAltText + * String to use as alt text + */ + public void setIcon(Resource icon, String iconAltText) { + super.setIcon(icon); + getState().iconAltText = iconAltText == null ? "" : iconAltText; + } + + /** + * Returns the icon's alt text. + * + * @return String with the alt text + */ + public String getIconAlternateText() { + return getState(false).iconAltText; + } + + public void setIconAlternateText(String iconAltText) { + getState().iconAltText = iconAltText; + } + + /** + * Set whether the caption text is rendered as HTML or not. You might need + * to re-theme button to allow higher content than the original text style. + * + * If set to true, the captions are passed to the browser as html and the + * developer is responsible for ensuring no harmful html is used. If set to + * false, the content is passed to the browser as plain text. + * + * @param htmlContentAllowed + * <code>true</code> if caption is rendered as HTML, + * <code>false</code> otherwise + */ + public void setHtmlContentAllowed(boolean htmlContentAllowed) { + getState().captionAsHtml = htmlContentAllowed; + } + + /** + * Return HTML rendering setting + * + * @return <code>true</code> if the caption text is to be rendered as HTML, + * <code>false</code> otherwise + */ + public boolean isHtmlContentAllowed() { + return getState(false).captionAsHtml; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.AbstractComponent#readDesign(org.jsoup.nodes .Element, + * com.vaadin.ui.declarative.DesignContext) + */ + @Override + public void readDesign(Element design, DesignContext designContext) { + super.readDesign(design, designContext); + Attributes attr = design.attributes(); + String content; + // plain-text (default is html) + Boolean plain = DesignAttributeHandler.readAttribute( + DESIGN_ATTR_PLAIN_TEXT, attr, Boolean.class); + if (plain == null || !plain) { + setHtmlContentAllowed(true); + content = design.html(); + } else { + // content is not intended to be interpreted as HTML, + // so html entities need to be decoded + content = DesignFormatter.decodeFromTextNode(design.html()); + } + setCaption(content); + if (attr.hasKey("icon-alt")) { + setIconAlternateText(DesignAttributeHandler.readAttribute( + "icon-alt", attr, String.class)); + } + // click-shortcut + removeClickShortcut(); + ShortcutAction action = DesignAttributeHandler.readAttribute( + "click-shortcut", attr, ShortcutAction.class); + if (action != null) { + setClickShortcut(action.getKeyCode(), action.getModifiers()); + } + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.AbstractComponent#getCustomAttributes() + */ + @Override + protected Collection<String> getCustomAttributes() { + Collection<String> result = super.getCustomAttributes(); + result.add(DESIGN_ATTR_PLAIN_TEXT); + result.add("caption"); + result.add("icon-alt"); + result.add("icon-alternate-text"); + result.add("click-shortcut"); + result.add("html-content-allowed"); + result.add("caption-as-html"); + return result; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.AbstractComponent#writeDesign(org.jsoup.nodes.Element + * , com.vaadin.ui.declarative.DesignContext) + */ + @Override + public void writeDesign(Element design, DesignContext designContext) { + super.writeDesign(design, designContext); + Attributes attr = design.attributes(); + Button def = (Button) designContext.getDefaultInstance(this); + String content = getCaption(); + if (content != null) { + design.html(content); + } + // plain-text (default is html) + if (!isHtmlContentAllowed()) { + design.attr(DESIGN_ATTR_PLAIN_TEXT, true); + // encode HTML entities + if (content != null) { + design.html(DesignFormatter.encodeForTextNode(content)); + } + } + // icon-alt + DesignAttributeHandler.writeAttribute("icon-alt", attr, + getIconAlternateText(), def.getIconAlternateText(), + String.class); + // click-shortcut + if (clickShortcut != null) { + DesignAttributeHandler.writeAttribute("click-shortcut", attr, + clickShortcut, null, ShortcutAction.class); + } + } +} |