Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

Notification.java 18KB

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