/* * Copyright 2000-2016 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 com.vaadin.event.ConnectorEvent; import com.vaadin.server.AbstractExtension; import com.vaadin.server.Page; import com.vaadin.server.Resource; import com.vaadin.shared.Position; import com.vaadin.shared.Registration; import com.vaadin.shared.ui.notification.NotificationServerRpc; import com.vaadin.shared.ui.notification.NotificationState; /** * A notification message, used to display temporary messages to the user - for * example "Document saved", or "Save failed". *

* The notification message can consist of several parts: caption, description * and icon. It is usually used with only caption - one should be wary of * filling the notification with too much information. *

*

* The notification message tries to be as unobtrusive as possible, while still * drawing needed attention. There are several basic types of messages that can * be used in different situations: *

*

*

* In addition to the basic pre-configured types, a Notification can also be * configured to show up in a custom position, for a specified time (or until * clicked), and with a custom stylename. An icon can also be added. *

* */ public class Notification extends AbstractExtension { /** * The server RPC. * * @since 8.2 */ protected NotificationServerRpc rpc = () -> fireEvent( new CloseEvent(Notification.this)); public enum Type { HUMANIZED_MESSAGE("humanized"), WARNING_MESSAGE( "warning"), ERROR_MESSAGE("error"), TRAY_NOTIFICATION("tray"), /** * @since 7.2 */ ASSISTIVE_NOTIFICATION("assistive"); private final String style; Type(String style) { this.style = style; } /** * @since 7.2 * * @return the style name for this notification type. */ public String getStyle() { return style; } } @Deprecated public static final Type TYPE_HUMANIZED_MESSAGE = Type.HUMANIZED_MESSAGE; @Deprecated public static final Type TYPE_WARNING_MESSAGE = Type.WARNING_MESSAGE; @Deprecated public static final Type TYPE_ERROR_MESSAGE = Type.ERROR_MESSAGE; @Deprecated public static final Type TYPE_TRAY_NOTIFICATION = Type.TRAY_NOTIFICATION; @Deprecated public static final Position POSITION_CENTERED = Position.MIDDLE_CENTER; @Deprecated public static final Position POSITION_CENTERED_TOP = Position.TOP_CENTER; @Deprecated public static final Position POSITION_CENTERED_BOTTOM = Position.BOTTOM_CENTER; @Deprecated public static final Position POSITION_TOP_LEFT = Position.TOP_LEFT; @Deprecated public static final Position POSITION_TOP_RIGHT = Position.TOP_RIGHT; @Deprecated public static final Position POSITION_BOTTOM_LEFT = Position.BOTTOM_LEFT; @Deprecated public static final Position POSITION_BOTTOM_RIGHT = Position.BOTTOM_RIGHT; public static final int DELAY_FOREVER = -1; public static final int DELAY_NONE = 0; /** * Creates a "humanized" notification message. * * The caption is rendered as plain text with HTML automatically escaped. * * @param caption * The message to show */ public Notification(String caption) { this(caption, null, TYPE_HUMANIZED_MESSAGE); } /** * Creates a notification message of the specified type. * * The caption is rendered as plain text with HTML automatically escaped. * * @param caption * The message to show * @param type * The type of message */ public Notification(String caption, Type type) { this(caption, null, type); } /** * Creates a "humanized" notification message with a bigger caption and * smaller description. * * The caption and description are rendered as plain text with HTML * automatically escaped. * * @param caption * The message caption * @param description * The message description */ public Notification(String caption, String description) { this(caption, description, TYPE_HUMANIZED_MESSAGE); } /** * Creates a notification message of the specified type, with a bigger * caption and smaller description. * * The caption and description are rendered as plain text with HTML * automatically escaped. * * @param caption * The message caption * @param description * The message description * @param type * The type of message */ public Notification(String caption, String description, Type type) { this(caption, description, type, false); } /** * Creates a notification message of the specified type, with a bigger * caption and smaller description. * * Care should be taken to to avoid XSS vulnerabilities if html is allowed. * * @param caption * The message caption * @param description * The message description * @param type * The type of message * @param htmlContentAllowed * Whether html in the caption and description should be * displayed as html or as plain text */ public Notification(String caption, String description, Type type, boolean htmlContentAllowed) { registerRpc(rpc); setCaption(caption); setDescription(description); setHtmlContentAllowed(htmlContentAllowed); setType(type); } private void setType(Type type) { setStyleName(type.getStyle()); switch (type) { case WARNING_MESSAGE: setDelayMsec(1500); break; case ERROR_MESSAGE: setDelayMsec(DELAY_FOREVER); break; case TRAY_NOTIFICATION: setDelayMsec(3000); setPosition(Position.BOTTOM_RIGHT); break; case ASSISTIVE_NOTIFICATION: setDelayMsec(3000); setPosition(Position.ASSISTIVE); break; case HUMANIZED_MESSAGE: default: break; } } /** * Gets the caption part of the notification message. * * @return The message caption */ public String getCaption() { return getState(false).caption; } /** * Sets the caption part of the notification message. * * @param caption * The message caption */ public void setCaption(String caption) { getState().caption = caption; } /** * Gets the description part of the notification message. * * @return The message description */ public String getDescription() { return getState(false).description; } /** * Sets the description part of the notification message. * * @param description * The message description */ public void setDescription(String description) { getState().description = description; } /** * Gets the position of the notification message. * * @return The position */ public Position getPosition() { return getState(false).position; } /** * Sets the position of the notification message. * * @param position * The desired notification position, not {@code null} */ public void setPosition(Position position) { if (position == null) { throw new IllegalArgumentException("Position can not be null"); } getState().position = position; } /** * Gets the icon part of the notification message. * * @return The message icon */ public Resource getIcon() { return getResource("icon"); } /** * Sets the icon part of the notification message. * * @param icon * The desired message icon */ public void setIcon(Resource icon) { setResource("icon", icon); } /** * Gets the delay before the notification disappears. * * @return the delay in milliseconds, {@value #DELAY_FOREVER} indicates the * message has to be clicked. */ public int getDelayMsec() { return getState(false).delay; } /** * Sets the delay before the notification disappears. * * @param delayMsec * the desired delay in milliseconds, {@value #DELAY_FOREVER} to * require the user to click the message */ public void setDelayMsec(int delayMsec) { getState().delay = delayMsec; } /** * Sets the style name for the notification message. * * @param styleName * The desired style name */ public void setStyleName(String styleName) { getState().styleName = styleName; } /** * Gets the style name for the notification message. * * @return The style name */ public String getStyleName() { return getState(false).styleName; } /** * Sets whether html is allowed in the caption and description. If set to * true, the texts are passed to the browser as html and the developer is * responsible for ensuring no harmful html is used. If set to false, the * texts are passed to the browser as plain text. * * @param htmlContentAllowed * true if the texts are used as html, false if used as plain * text */ public void setHtmlContentAllowed(boolean htmlContentAllowed) { getState().htmlContentAllowed = htmlContentAllowed; } /** * Checks whether caption and description are interpreted as HTML or plain * text. * * @return {@code true} if the texts are used as HTML, {@code false} if used * as plain text * @see #setHtmlContentAllowed(boolean) */ public boolean isHtmlContentAllowed() { return getState(false).htmlContentAllowed; } /** * Shows this notification on a Page. * * @param page * The page on which the notification should be shown */ public void show(Page page) { extend(page.getUI()); } @Override protected NotificationState getState() { return (NotificationState) super.getState(); } @Override protected NotificationState getState(boolean markAsDirty) { return (NotificationState) super.getState(markAsDirty); } /** * Shows a notification message on the middle of the current page. The * message automatically disappears ("humanized message"). * * The caption is rendered as plain text with HTML automatically escaped. * * @see #Notification(String) * @see #show(Page) * * @param caption * The message * @return The Notification */ public static Notification show(String caption) { Notification notification = new Notification(caption); notification.extend(UI.getCurrent()); return notification; } /** * Shows a notification message the current page. The position and behavior * of the message depends on the type, which is one of the basic types * defined in {@link Notification}, for instance * {@link Type#WARNING_MESSAGE}. * * The caption is rendered as plain text with HTML automatically escaped. * * @see Notification(String, int) * @see #show(Page) * * @param caption * The message * @param type * The message type * @return The Notification */ public static Notification show(String caption, Type type) { Notification notification = new Notification(caption, type); notification.extend(UI.getCurrent()); return notification; } /** * Shows a notification message the current page. The position and behavior * of the message depends on the type, which is one of the basic types * defined in {@link Notification}, for instance * Notification.TYPE_WARNING_MESSAGE. * * The caption is rendered as plain text with HTML automatically escaped. * * @see #Notification(String, Type) * @see #show(Page) * * @param caption * The message * @param description * The message description * @param type * The message type * @return The Notification */ public static Notification show(String caption, String description, Type type) { Notification notification = new Notification(caption, description, type); notification.extend(UI.getCurrent()); return notification; } /** * Adds a CloseListener to the Notification. * * @param listener * the CloseListener to add, not {@code null} * @since 8.2 */ public Registration addCloseListener(CloseListener listener) { return addListener(CloseEvent.class, listener, CLOSE_METHOD); } private static final Method CLOSE_METHOD; static { try { CLOSE_METHOD = CloseListener.class .getDeclaredMethod("notificationClose", CloseEvent.class); } catch (final NoSuchMethodException e) { // This should never happen throw new RuntimeException( "Internal error, notification close method not found"); } } /** * Event fired when a notification is closed. * * @since 8.2 */ public static class CloseEvent extends ConnectorEvent { /** * @param source */ public CloseEvent(Notification source) { super(source); } /** * Gets the Notification. * * @return The Notification */ public Notification getNotification() { return (Notification) getSource(); } } /** * An interface used for listening to Notification close events. Add the * CloseListener to a Notification and * {@link CloseListener#notificationClose(CloseEvent)} will be called * whenever the Notification is closed. * * @since 8.2 */ @FunctionalInterface public interface CloseListener extends Serializable { /** * Use {@link CloseEvent#getNotification()} to get a reference to the * {@link Notification} that was closed. * * @param e * The triggered event */ public void notificationClose(CloseEvent e); } }