You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Notification.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. /*
  2. * Copyright 2000-2016 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.ui;
  17. import java.io.Serializable;
  18. import java.lang.reflect.Method;
  19. import com.vaadin.event.ConnectorEvent;
  20. import com.vaadin.server.AbstractExtension;
  21. import com.vaadin.server.Page;
  22. import com.vaadin.server.Resource;
  23. import com.vaadin.shared.Position;
  24. import com.vaadin.shared.Registration;
  25. import com.vaadin.shared.ui.notification.NotificationServerRpc;
  26. import com.vaadin.shared.ui.notification.NotificationState;
  27. /**
  28. * A notification message, used to display temporary messages to the user - for
  29. * example "Document saved", or "Save failed".
  30. * <p>
  31. * The notification message can consist of several parts: caption, description
  32. * and icon. It is usually used with only caption - one should be wary of
  33. * filling the notification with too much information.
  34. * </p>
  35. * <p>
  36. * The notification message tries to be as unobtrusive as possible, while still
  37. * drawing needed attention. There are several basic types of messages that can
  38. * be used in different situations:
  39. * <ul>
  40. * <li>TYPE_HUMANIZED_MESSAGE fades away quickly as soon as the user uses the
  41. * mouse or types something. It can be used to show fairly unimportant messages,
  42. * such as feedback that an operation succeeded ("Document Saved") - the kind of
  43. * messages the user ignores once the application is familiar.</li>
  44. * <li>TYPE_WARNING_MESSAGE is shown for a short while after the user uses the
  45. * mouse or types something. It's default style is also more noticeable than the
  46. * humanized message. It can be used for messages that do not contain a lot of
  47. * important information, but should be noticed by the user. Despite the name,
  48. * it does not have to be a warning, but can be used instead of the humanized
  49. * message whenever you want to make the message a little more noticeable.</li>
  50. * <li>TYPE_ERROR_MESSAGE requires to user to click it before disappearing, and
  51. * can be used for critical messages.</li>
  52. * <li>TYPE_TRAY_NOTIFICATION is shown for a while in the lower left corner of
  53. * the window, and can be used for "convenience notifications" that do not have
  54. * to be noticed immediately, and should not interfere with the current task -
  55. * for instance to show "You have a new message in your inbox" while the user is
  56. * working in some other area of the application.</li>
  57. * </ul>
  58. * </p>
  59. * <p>
  60. * In addition to the basic pre-configured types, a Notification can also be
  61. * configured to show up in a custom position, for a specified time (or until
  62. * clicked), and with a custom stylename. An icon can also be added.
  63. * </p>
  64. *
  65. */
  66. public class Notification extends AbstractExtension implements Serializable {
  67. /**
  68. * The server RPC.
  69. *
  70. * @since 8.2
  71. */
  72. protected NotificationServerRpc rpc = () -> {
  73. fireEvent(new CloseEvent(Notification.this));
  74. };
  75. public enum Type {
  76. HUMANIZED_MESSAGE("humanized"), WARNING_MESSAGE(
  77. "warning"), ERROR_MESSAGE("error"), TRAY_NOTIFICATION("tray"),
  78. /**
  79. * @since 7.2
  80. */
  81. ASSISTIVE_NOTIFICATION("assistive");
  82. private final String style;
  83. Type(String style) {
  84. this.style = style;
  85. }
  86. /**
  87. * @since 7.2
  88. *
  89. * @return the style name for this notification type.
  90. */
  91. public String getStyle() {
  92. return style;
  93. }
  94. }
  95. @Deprecated
  96. public static final Type TYPE_HUMANIZED_MESSAGE = Type.HUMANIZED_MESSAGE;
  97. @Deprecated
  98. public static final Type TYPE_WARNING_MESSAGE = Type.WARNING_MESSAGE;
  99. @Deprecated
  100. public static final Type TYPE_ERROR_MESSAGE = Type.ERROR_MESSAGE;
  101. @Deprecated
  102. public static final Type TYPE_TRAY_NOTIFICATION = Type.TRAY_NOTIFICATION;
  103. @Deprecated
  104. public static final Position POSITION_CENTERED = Position.MIDDLE_CENTER;
  105. @Deprecated
  106. public static final Position POSITION_CENTERED_TOP = Position.TOP_CENTER;
  107. @Deprecated
  108. public static final Position POSITION_CENTERED_BOTTOM = Position.BOTTOM_CENTER;
  109. @Deprecated
  110. public static final Position POSITION_TOP_LEFT = Position.TOP_LEFT;
  111. @Deprecated
  112. public static final Position POSITION_TOP_RIGHT = Position.TOP_RIGHT;
  113. @Deprecated
  114. public static final Position POSITION_BOTTOM_LEFT = Position.BOTTOM_LEFT;
  115. @Deprecated
  116. public static final Position POSITION_BOTTOM_RIGHT = Position.BOTTOM_RIGHT;
  117. public static final int DELAY_FOREVER = -1;
  118. public static final int DELAY_NONE = 0;
  119. /**
  120. * Creates a "humanized" notification message.
  121. *
  122. * The caption is rendered as plain text with HTML automatically escaped.
  123. *
  124. * @param caption
  125. * The message to show
  126. */
  127. public Notification(String caption) {
  128. this(caption, null, TYPE_HUMANIZED_MESSAGE);
  129. }
  130. /**
  131. * Creates a notification message of the specified type.
  132. *
  133. * The caption is rendered as plain text with HTML automatically escaped.
  134. *
  135. * @param caption
  136. * The message to show
  137. * @param type
  138. * The type of message
  139. */
  140. public Notification(String caption, Type type) {
  141. this(caption, null, type);
  142. }
  143. /**
  144. * Creates a "humanized" notification message with a bigger caption and
  145. * smaller description.
  146. *
  147. * The caption and description are rendered as plain text with HTML
  148. * automatically escaped.
  149. *
  150. * @param caption
  151. * The message caption
  152. * @param description
  153. * The message description
  154. */
  155. public Notification(String caption, String description) {
  156. this(caption, description, TYPE_HUMANIZED_MESSAGE);
  157. }
  158. /**
  159. * Creates a notification message of the specified type, with a bigger
  160. * caption and smaller description.
  161. *
  162. * The caption and description are rendered as plain text with HTML
  163. * automatically escaped.
  164. *
  165. * @param caption
  166. * The message caption
  167. * @param description
  168. * The message description
  169. * @param type
  170. * The type of message
  171. */
  172. public Notification(String caption, String description, Type type) {
  173. this(caption, description, type, false);
  174. }
  175. /**
  176. * Creates a notification message of the specified type, with a bigger
  177. * caption and smaller description.
  178. *
  179. * Care should be taken to to avoid XSS vulnerabilities if html is allowed.
  180. *
  181. * @param caption
  182. * The message caption
  183. * @param description
  184. * The message description
  185. * @param type
  186. * The type of message
  187. * @param htmlContentAllowed
  188. * Whether html in the caption and description should be
  189. * displayed as html or as plain text
  190. */
  191. public Notification(String caption, String description, Type type,
  192. boolean htmlContentAllowed) {
  193. registerRpc(rpc);
  194. setCaption(caption);
  195. setDescription(description);
  196. setHtmlContentAllowed(htmlContentAllowed);
  197. setType(type);
  198. }
  199. private void setType(Type type) {
  200. setStyleName(type.getStyle());
  201. switch (type) {
  202. case WARNING_MESSAGE:
  203. setDelayMsec(1500);
  204. break;
  205. case ERROR_MESSAGE:
  206. setDelayMsec(DELAY_FOREVER);
  207. break;
  208. case TRAY_NOTIFICATION:
  209. setDelayMsec(3000);
  210. setPosition(Position.BOTTOM_RIGHT);
  211. break;
  212. case ASSISTIVE_NOTIFICATION:
  213. setDelayMsec(3000);
  214. setPosition(Position.ASSISTIVE);
  215. break;
  216. case HUMANIZED_MESSAGE:
  217. default:
  218. break;
  219. }
  220. }
  221. /**
  222. * Gets the caption part of the notification message.
  223. *
  224. * @return The message caption
  225. */
  226. public String getCaption() {
  227. return getState(false).caption;
  228. }
  229. /**
  230. * Sets the caption part of the notification message.
  231. *
  232. * @param caption
  233. * The message caption
  234. */
  235. public void setCaption(String caption) {
  236. getState().caption = caption;
  237. }
  238. /**
  239. * Gets the description part of the notification message.
  240. *
  241. * @return The message description
  242. */
  243. public String getDescription() {
  244. return getState(false).description;
  245. }
  246. /**
  247. * Sets the description part of the notification message.
  248. *
  249. * @param description
  250. * The message description
  251. */
  252. public void setDescription(String description) {
  253. getState().description = description;
  254. }
  255. /**
  256. * Gets the position of the notification message.
  257. *
  258. * @return The position
  259. */
  260. public Position getPosition() {
  261. return getState(false).position;
  262. }
  263. /**
  264. * Sets the position of the notification message.
  265. *
  266. * @param position
  267. * The desired notification position, not {@code null}
  268. */
  269. public void setPosition(Position position) {
  270. if (position == null) {
  271. throw new IllegalArgumentException("Position can not be null");
  272. }
  273. getState().position = position;
  274. }
  275. /**
  276. * Gets the icon part of the notification message.
  277. *
  278. * @return The message icon
  279. */
  280. public Resource getIcon() {
  281. return getResource("icon");
  282. }
  283. /**
  284. * Sets the icon part of the notification message.
  285. *
  286. * @param icon
  287. * The desired message icon
  288. */
  289. public void setIcon(Resource icon) {
  290. setResource("icon", icon);
  291. }
  292. /**
  293. * Gets the delay before the notification disappears.
  294. *
  295. * @return the delay in milliseconds, {@value #DELAY_FOREVER} indicates the
  296. * message has to be clicked.
  297. */
  298. public int getDelayMsec() {
  299. return getState(false).delay;
  300. }
  301. /**
  302. * Sets the delay before the notification disappears.
  303. *
  304. * @param delayMsec
  305. * the desired delay in milliseconds, {@value #DELAY_FOREVER} to
  306. * require the user to click the message
  307. */
  308. public void setDelayMsec(int delayMsec) {
  309. getState().delay = delayMsec;
  310. }
  311. /**
  312. * Sets the style name for the notification message.
  313. *
  314. * @param styleName
  315. * The desired style name
  316. */
  317. public void setStyleName(String styleName) {
  318. getState().styleName = styleName;
  319. }
  320. /**
  321. * Gets the style name for the notification message.
  322. *
  323. * @return The style name
  324. */
  325. public String getStyleName() {
  326. return getState(false).styleName;
  327. }
  328. /**
  329. * Sets whether html is allowed in the caption and description. If set to
  330. * true, the texts are passed to the browser as html and the developer is
  331. * responsible for ensuring no harmful html is used. If set to false, the
  332. * texts are passed to the browser as plain text.
  333. *
  334. * @param htmlContentAllowed
  335. * true if the texts are used as html, false if used as plain
  336. * text
  337. */
  338. public void setHtmlContentAllowed(boolean htmlContentAllowed) {
  339. getState().htmlContentAllowed = htmlContentAllowed;
  340. }
  341. /**
  342. * Checks whether caption and description are interpreted as HTML or plain
  343. * text.
  344. *
  345. * @return {@code true} if the texts are used as HTML, {@code false} if used
  346. * as plain text
  347. * @see #setHtmlContentAllowed(boolean)
  348. */
  349. public boolean isHtmlContentAllowed() {
  350. return getState(false).htmlContentAllowed;
  351. }
  352. /**
  353. * Shows this notification on a Page.
  354. *
  355. * @param page
  356. * The page on which the notification should be shown
  357. */
  358. public void show(Page page) {
  359. extend(page.getUI());
  360. }
  361. @Override
  362. protected NotificationState getState() {
  363. return (NotificationState) super.getState();
  364. }
  365. @Override
  366. protected NotificationState getState(boolean markAsDirty) {
  367. return (NotificationState) super.getState(markAsDirty);
  368. }
  369. /**
  370. * Shows a notification message on the middle of the current page. The
  371. * message automatically disappears ("humanized message").
  372. *
  373. * The caption is rendered as plain text with HTML automatically escaped.
  374. *
  375. * @see #Notification(String)
  376. * @see #show(Page)
  377. *
  378. * @param caption
  379. * The message
  380. * @return The Notification
  381. */
  382. public static Notification show(String caption) {
  383. Notification notification = new Notification(caption);
  384. notification.extend(UI.getCurrent());
  385. return notification;
  386. }
  387. /**
  388. * Shows a notification message the current page. The position and behavior
  389. * of the message depends on the type, which is one of the basic types
  390. * defined in {@link Notification}, for instance
  391. * {@link Type#WARNING_MESSAGE}.
  392. *
  393. * The caption is rendered as plain text with HTML automatically escaped.
  394. *
  395. * @see Notification(String, int)
  396. * @see #show(Page)
  397. *
  398. * @param caption
  399. * The message
  400. * @param type
  401. * The message type
  402. * @return The Notification
  403. */
  404. public static Notification show(String caption, Type type) {
  405. Notification notification = new Notification(caption, type);
  406. notification.extend(UI.getCurrent());
  407. return notification;
  408. }
  409. /**
  410. * Shows a notification message the current page. The position and behavior
  411. * of the message depends on the type, which is one of the basic types
  412. * defined in {@link Notification}, for instance
  413. * Notification.TYPE_WARNING_MESSAGE.
  414. *
  415. * The caption is rendered as plain text with HTML automatically escaped.
  416. *
  417. * @see #Notification(String, Type)
  418. * @see #show(Page)
  419. *
  420. * @param caption
  421. * The message
  422. * @param description
  423. * The message description
  424. * @param type
  425. * The message type
  426. * @return The Notification
  427. */
  428. public static Notification show(String caption, String description,
  429. Type type) {
  430. Notification notification = new Notification(caption, description,
  431. type);
  432. notification.extend(UI.getCurrent());
  433. return notification;
  434. }
  435. /**
  436. * Adds a CloseListener to the Notification.
  437. *
  438. * @param listener
  439. * the CloseListener to add, not {@code null}
  440. * @since 8.2
  441. */
  442. public Registration addCloseListener(CloseListener listener) {
  443. return addListener(CloseEvent.class, listener, CLOSE_METHOD);
  444. }
  445. private static final Method CLOSE_METHOD;
  446. static {
  447. try {
  448. CLOSE_METHOD = CloseListener.class
  449. .getDeclaredMethod("notificationClose", CloseEvent.class);
  450. } catch (final NoSuchMethodException e) {
  451. // This should never happen
  452. throw new RuntimeException(
  453. "Internal error, notification close method not found");
  454. }
  455. }
  456. /**
  457. * Event fired when a notification is closed.
  458. *
  459. * @since 8.2
  460. */
  461. public static class CloseEvent extends ConnectorEvent {
  462. /**
  463. * @param source
  464. */
  465. public CloseEvent(Notification source) {
  466. super(source);
  467. }
  468. /**
  469. * Gets the Notification.
  470. *
  471. * @return The Notification
  472. */
  473. public Notification getNotification() {
  474. return (Notification) getSource();
  475. }
  476. }
  477. /**
  478. * An interface used for listening to Notification close events. Add the
  479. * CloseListener to a Notification and
  480. * {@link CloseListener#notificationClose(CloseEvent)} will be called
  481. * whenever the Notification is closed.
  482. *
  483. * @since 8.2
  484. */
  485. @FunctionalInterface
  486. public interface CloseListener extends Serializable {
  487. /**
  488. * Use {@link CloseEvent#getNotification()} to get a reference to the
  489. * {@link Notification} that was closed.
  490. *
  491. * @param e
  492. * The triggered event
  493. */
  494. public void notificationClose(CloseEvent e);
  495. }
  496. }