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.

Window.java 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844
  1. /*
  2. * Copyright 2011 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 java.util.Map;
  20. import com.vaadin.event.FieldEvents.BlurEvent;
  21. import com.vaadin.event.FieldEvents.BlurListener;
  22. import com.vaadin.event.FieldEvents.BlurNotifier;
  23. import com.vaadin.event.FieldEvents.FocusEvent;
  24. import com.vaadin.event.FieldEvents.FocusListener;
  25. import com.vaadin.event.FieldEvents.FocusNotifier;
  26. import com.vaadin.event.MouseEvents.ClickEvent;
  27. import com.vaadin.event.ShortcutAction;
  28. import com.vaadin.event.ShortcutAction.KeyCode;
  29. import com.vaadin.event.ShortcutAction.ModifierKey;
  30. import com.vaadin.event.ShortcutListener;
  31. import com.vaadin.shared.MouseEventDetails;
  32. import com.vaadin.shared.ui.window.WindowServerRpc;
  33. import com.vaadin.shared.ui.window.WindowState;
  34. import com.vaadin.terminal.PaintException;
  35. import com.vaadin.terminal.PaintTarget;
  36. import com.vaadin.terminal.Vaadin6Component;
  37. /**
  38. * A component that represents a floating popup window that can be added to a
  39. * {@link Root}. A window is added to a {@code Root} using
  40. * {@link Root#addWindow(Window)}. </p>
  41. * <p>
  42. * The contents of a window is set using {@link #setContent(ComponentContainer)}
  43. * or by using the {@link #Window(String, ComponentContainer)} constructor. The
  44. * contents can in turn contain other components. By default, a
  45. * {@link VerticalLayout} is used as content.
  46. * </p>
  47. * <p>
  48. * A window can be positioned on the screen using absolute coordinates (pixels)
  49. * or set to be centered using {@link #center()}
  50. * </p>
  51. * <p>
  52. * The caption is displayed in the window header.
  53. * </p>
  54. * <p>
  55. * In Vaadin versions prior to 7.0.0, Window was also used as application level
  56. * windows. This function is now covered by the {@link Root} class.
  57. * </p>
  58. *
  59. * @author Vaadin Ltd.
  60. * @since 3.0
  61. */
  62. @SuppressWarnings("serial")
  63. public class Window extends Panel implements FocusNotifier, BlurNotifier,
  64. Vaadin6Component {
  65. private WindowServerRpc rpc = new WindowServerRpc() {
  66. @Override
  67. public void click(MouseEventDetails mouseDetails) {
  68. fireEvent(new ClickEvent(Window.this, mouseDetails));
  69. }
  70. };
  71. /**
  72. * Creates a new unnamed window with a default layout.
  73. */
  74. public Window() {
  75. this("", null);
  76. }
  77. /**
  78. * Creates a new unnamed window with a default layout and given title.
  79. *
  80. * @param caption
  81. * the title of the window.
  82. */
  83. public Window(String caption) {
  84. this(caption, null);
  85. }
  86. /**
  87. * Creates a new unnamed window with the given content and title.
  88. *
  89. * @param caption
  90. * the title of the window.
  91. * @param content
  92. * the contents of the window
  93. */
  94. public Window(String caption, ComponentContainer content) {
  95. super(caption, content);
  96. registerRpc(rpc);
  97. setSizeUndefined();
  98. }
  99. /*
  100. * (non-Javadoc)
  101. *
  102. * @see com.vaadin.ui.Panel#addComponent(com.vaadin.ui.Component)
  103. */
  104. @Override
  105. public void addComponent(Component c) {
  106. if (c instanceof Window) {
  107. throw new IllegalArgumentException(
  108. "Window cannot be added to another via addComponent. "
  109. + "Use addWindow(Window) instead.");
  110. }
  111. super.addComponent(c);
  112. }
  113. /* ********************************************************************* */
  114. /*
  115. * (non-Javadoc)
  116. *
  117. * @see com.vaadin.ui.Panel#paintContent(com.vaadin.terminal.PaintTarget)
  118. */
  119. @Override
  120. public synchronized void paintContent(PaintTarget target)
  121. throws PaintException {
  122. if (bringToFront != null) {
  123. target.addAttribute("bringToFront", bringToFront.intValue());
  124. bringToFront = null;
  125. }
  126. // Contents of the window panel is painted
  127. super.paintContent(target);
  128. }
  129. /*
  130. * (non-Javadoc)
  131. *
  132. * @see com.vaadin.ui.Panel#changeVariables(java.lang.Object, java.util.Map)
  133. */
  134. @Override
  135. public void changeVariables(Object source, Map<String, Object> variables) {
  136. // TODO Are these for top level windows or sub windows?
  137. boolean sizeHasChanged = false;
  138. // size is handled in super class, but resize events only in windows ->
  139. // so detect if size change occurs before super.changeVariables()
  140. if (variables.containsKey("height")
  141. && (getHeightUnits() != Unit.PIXELS || (Integer) variables
  142. .get("height") != getHeight())) {
  143. sizeHasChanged = true;
  144. }
  145. if (variables.containsKey("width")
  146. && (getWidthUnits() != Unit.PIXELS || (Integer) variables
  147. .get("width") != getWidth())) {
  148. sizeHasChanged = true;
  149. }
  150. super.changeVariables(source, variables);
  151. // Positioning
  152. final Integer positionx = (Integer) variables.get("positionx");
  153. if (positionx != null) {
  154. final int x = positionx.intValue();
  155. // This is information from the client so it is already using the
  156. // position. No need to repaint.
  157. setPositionX(x < 0 ? -1 : x, false);
  158. }
  159. final Integer positiony = (Integer) variables.get("positiony");
  160. if (positiony != null) {
  161. final int y = positiony.intValue();
  162. // This is information from the client so it is already using the
  163. // position. No need to repaint.
  164. setPositionY(y < 0 ? -1 : y, false);
  165. }
  166. if (isClosable()) {
  167. // Closing
  168. final Boolean close = (Boolean) variables.get("close");
  169. if (close != null && close.booleanValue()) {
  170. close();
  171. }
  172. }
  173. // fire event if size has really changed
  174. if (sizeHasChanged) {
  175. fireResize();
  176. }
  177. if (variables.containsKey(FocusEvent.EVENT_ID)) {
  178. fireEvent(new FocusEvent(this));
  179. } else if (variables.containsKey(BlurEvent.EVENT_ID)) {
  180. fireEvent(new BlurEvent(this));
  181. }
  182. }
  183. /**
  184. * Method that handles window closing (from UI).
  185. *
  186. * <p>
  187. * By default, sub-windows are removed from their respective parent windows
  188. * and thus visually closed on browser-side. Browser-level windows also
  189. * closed on the client-side, but they are not implicitly removed from the
  190. * application.
  191. * </p>
  192. *
  193. * <p>
  194. * To explicitly close a sub-window, use {@link #removeWindow(Window)}. To
  195. * react to a window being closed (after it is closed), register a
  196. * {@link CloseListener}.
  197. * </p>
  198. */
  199. public void close() {
  200. Root root = getRoot();
  201. // Don't do anything if not attached to a root
  202. if (root != null) {
  203. // focus is restored to the parent window
  204. root.focus();
  205. // subwindow is removed from the root
  206. root.removeWindow(this);
  207. }
  208. }
  209. /**
  210. * Gets the distance of Window left border in pixels from left border of the
  211. * containing (main window).
  212. *
  213. * @return the Distance of Window left border in pixels from left border of
  214. * the containing (main window). or -1 if unspecified.
  215. * @since 4.0.0
  216. */
  217. public int getPositionX() {
  218. return getState().getPositionX();
  219. }
  220. /**
  221. * Sets the distance of Window left border in pixels from left border of the
  222. * containing (main window).
  223. *
  224. * @param positionX
  225. * the Distance of Window left border in pixels from left border
  226. * of the containing (main window). or -1 if unspecified.
  227. * @since 4.0.0
  228. */
  229. public void setPositionX(int positionX) {
  230. setPositionX(positionX, true);
  231. }
  232. /**
  233. * Sets the distance of Window left border in pixels from left border of the
  234. * containing (main window).
  235. *
  236. * @param positionX
  237. * the Distance of Window left border in pixels from left border
  238. * of the containing (main window). or -1 if unspecified.
  239. * @param repaintRequired
  240. * true if the window needs to be repainted, false otherwise
  241. * @since 6.3.4
  242. */
  243. private void setPositionX(int positionX, boolean repaintRequired) {
  244. getState().setPositionX(positionX);
  245. getState().setCentered(false);
  246. if (repaintRequired) {
  247. requestRepaint();
  248. }
  249. }
  250. /**
  251. * Gets the distance of Window top border in pixels from top border of the
  252. * containing (main window).
  253. *
  254. * @return Distance of Window top border in pixels from top border of the
  255. * containing (main window). or -1 if unspecified .
  256. *
  257. * @since 4.0.0
  258. */
  259. public int getPositionY() {
  260. return getState().getPositionY();
  261. }
  262. /**
  263. * Sets the distance of Window top border in pixels from top border of the
  264. * containing (main window).
  265. *
  266. * @param positionY
  267. * the Distance of Window top border in pixels from top border of
  268. * the containing (main window). or -1 if unspecified
  269. *
  270. * @since 4.0.0
  271. */
  272. public void setPositionY(int positionY) {
  273. setPositionY(positionY, true);
  274. }
  275. /**
  276. * Sets the distance of Window top border in pixels from top border of the
  277. * containing (main window).
  278. *
  279. * @param positionY
  280. * the Distance of Window top border in pixels from top border of
  281. * the containing (main window). or -1 if unspecified
  282. * @param repaintRequired
  283. * true if the window needs to be repainted, false otherwise
  284. *
  285. * @since 6.3.4
  286. */
  287. private void setPositionY(int positionY, boolean repaintRequired) {
  288. getState().setPositionY(positionY);
  289. getState().setCentered(false);
  290. if (repaintRequired) {
  291. requestRepaint();
  292. }
  293. }
  294. private static final Method WINDOW_CLOSE_METHOD;
  295. static {
  296. try {
  297. WINDOW_CLOSE_METHOD = CloseListener.class.getDeclaredMethod(
  298. "windowClose", new Class[] { CloseEvent.class });
  299. } catch (final java.lang.NoSuchMethodException e) {
  300. // This should never happen
  301. throw new java.lang.RuntimeException(
  302. "Internal error, window close method not found");
  303. }
  304. }
  305. public class CloseEvent extends Component.Event {
  306. /**
  307. *
  308. * @param source
  309. */
  310. public CloseEvent(Component source) {
  311. super(source);
  312. }
  313. /**
  314. * Gets the Window.
  315. *
  316. * @return the window.
  317. */
  318. public Window getWindow() {
  319. return (Window) getSource();
  320. }
  321. }
  322. /**
  323. * An interface used for listening to Window close events. Add the
  324. * CloseListener to a browser level window or a sub window and
  325. * {@link CloseListener#windowClose(CloseEvent)} will be called whenever the
  326. * user closes the window.
  327. *
  328. * <p>
  329. * Since Vaadin 6.5, removing a window using {@link #removeWindow(Window)}
  330. * fires the CloseListener.
  331. * </p>
  332. */
  333. public interface CloseListener extends Serializable {
  334. /**
  335. * Called when the user closes a window. Use
  336. * {@link CloseEvent#getWindow()} to get a reference to the
  337. * {@link Window} that was closed.
  338. *
  339. * @param e
  340. * Event containing
  341. */
  342. public void windowClose(CloseEvent e);
  343. }
  344. /**
  345. * Adds a CloseListener to the window.
  346. *
  347. * For a sub window the CloseListener is fired when the user closes it
  348. * (clicks on the close button).
  349. *
  350. * For a browser level window the CloseListener is fired when the browser
  351. * level window is closed. Note that closing a browser level window does not
  352. * mean it will be destroyed. Also note that Opera does not send events like
  353. * all other browsers and therefore the close listener might not be called
  354. * if Opera is used.
  355. *
  356. * <p>
  357. * Since Vaadin 6.5, removing windows using {@link #removeWindow(Window)}
  358. * does fire the CloseListener.
  359. * </p>
  360. *
  361. * @param listener
  362. * the CloseListener to add.
  363. */
  364. public void addListener(CloseListener listener) {
  365. addListener(CloseEvent.class, listener, WINDOW_CLOSE_METHOD);
  366. }
  367. /**
  368. * Removes the CloseListener from the window.
  369. *
  370. * <p>
  371. * For more information on CloseListeners see {@link CloseListener}.
  372. * </p>
  373. *
  374. * @param listener
  375. * the CloseListener to remove.
  376. */
  377. public void removeListener(CloseListener listener) {
  378. removeListener(CloseEvent.class, listener, WINDOW_CLOSE_METHOD);
  379. }
  380. protected void fireClose() {
  381. fireEvent(new Window.CloseEvent(this));
  382. }
  383. /**
  384. * Method for the resize event.
  385. */
  386. private static final Method WINDOW_RESIZE_METHOD;
  387. static {
  388. try {
  389. WINDOW_RESIZE_METHOD = ResizeListener.class.getDeclaredMethod(
  390. "windowResized", new Class[] { ResizeEvent.class });
  391. } catch (final java.lang.NoSuchMethodException e) {
  392. // This should never happen
  393. throw new java.lang.RuntimeException(
  394. "Internal error, window resized method not found");
  395. }
  396. }
  397. /**
  398. * Resize events are fired whenever the client-side fires a resize-event
  399. * (e.g. the browser window is resized). The frequency may vary across
  400. * browsers.
  401. */
  402. public class ResizeEvent extends Component.Event {
  403. /**
  404. *
  405. * @param source
  406. */
  407. public ResizeEvent(Component source) {
  408. super(source);
  409. }
  410. /**
  411. * Get the window form which this event originated
  412. *
  413. * @return the window
  414. */
  415. public Window getWindow() {
  416. return (Window) getSource();
  417. }
  418. }
  419. /**
  420. * Listener for window resize events.
  421. *
  422. * @see com.vaadin.ui.Window.ResizeEvent
  423. */
  424. public interface ResizeListener extends Serializable {
  425. public void windowResized(ResizeEvent e);
  426. }
  427. /**
  428. * Add a resize listener.
  429. *
  430. * @param listener
  431. */
  432. public void addListener(ResizeListener listener) {
  433. addListener(ResizeEvent.class, listener, WINDOW_RESIZE_METHOD);
  434. }
  435. /**
  436. * Remove a resize listener.
  437. *
  438. * @param listener
  439. */
  440. public void removeListener(ResizeListener listener) {
  441. removeListener(ResizeEvent.class, listener);
  442. }
  443. /**
  444. * Fire the resize event.
  445. */
  446. protected void fireResize() {
  447. fireEvent(new ResizeEvent(this));
  448. }
  449. /**
  450. * Used to keep the right order of windows if multiple windows are brought
  451. * to front in a single changeset. If this is not used, the order is quite
  452. * random (depends on the order getting to dirty list. e.g. which window got
  453. * variable changes).
  454. */
  455. private Integer bringToFront = null;
  456. /**
  457. * If there are currently several windows visible, calling this method makes
  458. * this window topmost.
  459. * <p>
  460. * This method can only be called if this window connected a root. Else an
  461. * illegal state exception is thrown. Also if there are modal windows and
  462. * this window is not modal, and illegal state exception is thrown.
  463. * <p>
  464. */
  465. public void bringToFront() {
  466. Root root = getRoot();
  467. if (root == null) {
  468. throw new IllegalStateException(
  469. "Window must be attached to parent before calling bringToFront method.");
  470. }
  471. int maxBringToFront = -1;
  472. for (Window w : root.getWindows()) {
  473. if (!isModal() && w.isModal()) {
  474. throw new IllegalStateException(
  475. "The root contains modal windows, non-modal window cannot be brought to front.");
  476. }
  477. if (w.bringToFront != null) {
  478. maxBringToFront = Math.max(maxBringToFront,
  479. w.bringToFront.intValue());
  480. }
  481. }
  482. bringToFront = Integer.valueOf(maxBringToFront + 1);
  483. requestRepaint();
  484. }
  485. /**
  486. * Sets sub-window modal, so that widgets behind it cannot be accessed.
  487. * <b>Note:</b> affects sub-windows only.
  488. *
  489. * @param modal
  490. * true if modality is to be turned on
  491. */
  492. public void setModal(boolean modal) {
  493. getState().setModal(modal);
  494. center();
  495. requestRepaint();
  496. }
  497. /**
  498. * @return true if this window is modal.
  499. */
  500. public boolean isModal() {
  501. return getState().isModal();
  502. }
  503. /**
  504. * Sets sub-window resizable. <b>Note:</b> affects sub-windows only.
  505. *
  506. * @param resizable
  507. * true if resizability is to be turned on
  508. */
  509. public void setResizable(boolean resizable) {
  510. getState().setResizable(resizable);
  511. requestRepaint();
  512. }
  513. /**
  514. *
  515. * @return true if window is resizable by the end-user, otherwise false.
  516. */
  517. public boolean isResizable() {
  518. return getState().isResizable();
  519. }
  520. /**
  521. *
  522. * @return true if a delay is used before recalculating sizes, false if
  523. * sizes are recalculated immediately.
  524. */
  525. public boolean isResizeLazy() {
  526. return getState().isResizeLazy();
  527. }
  528. /**
  529. * Should resize operations be lazy, i.e. should there be a delay before
  530. * layout sizes are recalculated. Speeds up resize operations in slow UIs
  531. * with the penalty of slightly decreased usability.
  532. *
  533. * Note, some browser send false resize events for the browser window and
  534. * are therefore always lazy.
  535. *
  536. * @param resizeLazy
  537. * true to use a delay before recalculating sizes, false to
  538. * calculate immediately.
  539. */
  540. public void setResizeLazy(boolean resizeLazy) {
  541. getState().setResizeLazy(resizeLazy);
  542. requestRepaint();
  543. }
  544. /**
  545. * Sets this window to be centered relative to its parent window. Affects
  546. * sub-windows only. If the window is resized as a result of the size of its
  547. * content changing, it will keep itself centered as long as its position is
  548. * not explicitly changed programmatically or by the user.
  549. * <p>
  550. * <b>NOTE:</b> This method has several issues as currently implemented.
  551. * Please refer to http://dev.vaadin.com/ticket/8971 for details.
  552. */
  553. public void center() {
  554. getState().setCentered(true);
  555. requestRepaint();
  556. }
  557. /**
  558. * Returns the closable status of the sub window. If a sub window is
  559. * closable it typically shows an X in the upper right corner. Clicking on
  560. * the X sends a close event to the server. Setting closable to false will
  561. * remove the X from the sub window and prevent the user from closing the
  562. * window.
  563. *
  564. * Note! For historical reasons readonly controls the closability of the sub
  565. * window and therefore readonly and closable affect each other. Setting
  566. * readonly to true will set closable to false and vice versa.
  567. * <p/>
  568. * Closable only applies to sub windows, not to browser level windows.
  569. *
  570. * @return true if the sub window can be closed by the user.
  571. */
  572. public boolean isClosable() {
  573. return !isReadOnly();
  574. }
  575. /**
  576. * Sets the closable status for the sub window. If a sub window is closable
  577. * it typically shows an X in the upper right corner. Clicking on the X
  578. * sends a close event to the server. Setting closable to false will remove
  579. * the X from the sub window and prevent the user from closing the window.
  580. *
  581. * Note! For historical reasons readonly controls the closability of the sub
  582. * window and therefore readonly and closable affect each other. Setting
  583. * readonly to true will set closable to false and vice versa.
  584. * <p/>
  585. * Closable only applies to sub windows, not to browser level windows.
  586. *
  587. * @param closable
  588. * determines if the sub window can be closed by the user.
  589. */
  590. public void setClosable(boolean closable) {
  591. setReadOnly(!closable);
  592. }
  593. /**
  594. * Indicates whether a sub window can be dragged or not. By default a sub
  595. * window is draggable.
  596. * <p/>
  597. * Draggable only applies to sub windows, not to browser level windows.
  598. *
  599. * @param draggable
  600. * true if the sub window can be dragged by the user
  601. */
  602. public boolean isDraggable() {
  603. return getState().isDraggable();
  604. }
  605. /**
  606. * Enables or disables that a sub window can be dragged (moved) by the user.
  607. * By default a sub window is draggable.
  608. * <p/>
  609. * Draggable only applies to sub windows, not to browser level windows.
  610. *
  611. * @param draggable
  612. * true if the sub window can be dragged by the user
  613. */
  614. public void setDraggable(boolean draggable) {
  615. getState().setDraggable(draggable);
  616. requestRepaint();
  617. }
  618. /*
  619. * Actions
  620. */
  621. protected CloseShortcut closeShortcut;
  622. /**
  623. * Makes is possible to close the window by pressing the given
  624. * {@link KeyCode} and (optional) {@link ModifierKey}s.<br/>
  625. * Note that this shortcut only reacts while the window has focus, closing
  626. * itself - if you want to close a subwindow from a parent window, use
  627. * {@link #addAction(com.vaadin.event.Action)} of the parent window instead.
  628. *
  629. * @param keyCode
  630. * the keycode for invoking the shortcut
  631. * @param modifiers
  632. * the (optional) modifiers for invoking the shortcut, null for
  633. * none
  634. */
  635. public void setCloseShortcut(int keyCode, int... modifiers) {
  636. if (closeShortcut != null) {
  637. removeAction(closeShortcut);
  638. }
  639. closeShortcut = new CloseShortcut(this, keyCode, modifiers);
  640. addAction(closeShortcut);
  641. }
  642. /**
  643. * Removes the keyboard shortcut previously set with
  644. * {@link #setCloseShortcut(int, int...)}.
  645. */
  646. public void removeCloseShortcut() {
  647. if (closeShortcut != null) {
  648. removeAction(closeShortcut);
  649. closeShortcut = null;
  650. }
  651. }
  652. /**
  653. * A {@link ShortcutListener} specifically made to define a keyboard
  654. * shortcut that closes the window.
  655. *
  656. * <pre>
  657. * <code>
  658. * // within the window using helper
  659. * subWindow.setCloseShortcut(KeyCode.ESCAPE, null);
  660. *
  661. * // or globally
  662. * getWindow().addAction(new Window.CloseShortcut(subWindow, KeyCode.ESCAPE));
  663. * </code>
  664. * </pre>
  665. *
  666. */
  667. public static class CloseShortcut extends ShortcutListener {
  668. protected Window window;
  669. /**
  670. * Creates a keyboard shortcut for closing the given window using the
  671. * shorthand notation defined in {@link ShortcutAction}.
  672. *
  673. * @param window
  674. * to be closed when the shortcut is invoked
  675. * @param shorthandCaption
  676. * the caption with shortcut keycode and modifiers indicated
  677. */
  678. public CloseShortcut(Window window, String shorthandCaption) {
  679. super(shorthandCaption);
  680. this.window = window;
  681. }
  682. /**
  683. * Creates a keyboard shortcut for closing the given window using the
  684. * given {@link KeyCode} and {@link ModifierKey}s.
  685. *
  686. * @param window
  687. * to be closed when the shortcut is invoked
  688. * @param keyCode
  689. * KeyCode to react to
  690. * @param modifiers
  691. * optional modifiers for shortcut
  692. */
  693. public CloseShortcut(Window window, int keyCode, int... modifiers) {
  694. super(null, keyCode, modifiers);
  695. this.window = window;
  696. }
  697. /**
  698. * Creates a keyboard shortcut for closing the given window using the
  699. * given {@link KeyCode}.
  700. *
  701. * @param window
  702. * to be closed when the shortcut is invoked
  703. * @param keyCode
  704. * KeyCode to react to
  705. */
  706. public CloseShortcut(Window window, int keyCode) {
  707. this(window, keyCode, null);
  708. }
  709. @Override
  710. public void handleAction(Object sender, Object target) {
  711. window.close();
  712. }
  713. }
  714. /**
  715. * Note, that focus/blur listeners in Window class are only supported by sub
  716. * windows. Also note that Window is not considered focused if its contained
  717. * component currently has focus.
  718. *
  719. * @see com.vaadin.event.FieldEvents.FocusNotifier#addListener(com.vaadin.event.FieldEvents.FocusListener)
  720. */
  721. @Override
  722. public void addListener(FocusListener listener) {
  723. addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
  724. FocusListener.focusMethod);
  725. }
  726. @Override
  727. public void removeListener(FocusListener listener) {
  728. removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
  729. }
  730. /**
  731. * Note, that focus/blur listeners in Window class are only supported by sub
  732. * windows. Also note that Window is not considered focused if its contained
  733. * component currently has focus.
  734. *
  735. * @see com.vaadin.event.FieldEvents.BlurNotifier#addListener(com.vaadin.event.FieldEvents.BlurListener)
  736. */
  737. @Override
  738. public void addListener(BlurListener listener) {
  739. addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
  740. BlurListener.blurMethod);
  741. }
  742. @Override
  743. public void removeListener(BlurListener listener) {
  744. removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
  745. }
  746. /**
  747. * {@inheritDoc}
  748. *
  749. * If the window is a sub-window focusing will cause the sub-window to be
  750. * brought on top of other sub-windows on gain keyboard focus.
  751. */
  752. @Override
  753. public void focus() {
  754. /*
  755. * When focusing a sub-window it basically means it should be brought to
  756. * the front. Instead of just moving the keyboard focus we focus the
  757. * window and bring it top-most.
  758. */
  759. super.focus();
  760. bringToFront();
  761. }
  762. @Override
  763. public WindowState getState() {
  764. return (WindowState) super.getState();
  765. }
  766. }