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 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  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 UI}. A window is added to a {@code UI} using
  40. * {@link UI#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 UI} 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);
  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);
  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. UI uI = getUI();
  201. // Don't do anything if not attached to a UI
  202. if (uI != null) {
  203. // focus is restored to the parent window
  204. uI.focus();
  205. // subwindow is removed from the UI
  206. uI.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. getState().setPositionX(positionX);
  231. getState().setCentered(false);
  232. }
  233. /**
  234. * Gets the distance of Window top border in pixels from top border of the
  235. * containing (main window).
  236. *
  237. * @return Distance of Window top border in pixels from top border of the
  238. * containing (main window). or -1 if unspecified .
  239. *
  240. * @since 4.0.0
  241. */
  242. public int getPositionY() {
  243. return getState().getPositionY();
  244. }
  245. /**
  246. * Sets the distance of Window top border in pixels from top border of the
  247. * containing (main window).
  248. *
  249. * @param positionY
  250. * the Distance of Window top border in pixels from top border of
  251. * the containing (main window). or -1 if unspecified
  252. *
  253. * @since 4.0.0
  254. */
  255. public void setPositionY(int positionY) {
  256. getState().setPositionY(positionY);
  257. getState().setCentered(false);
  258. }
  259. private static final Method WINDOW_CLOSE_METHOD;
  260. static {
  261. try {
  262. WINDOW_CLOSE_METHOD = CloseListener.class.getDeclaredMethod(
  263. "windowClose", new Class[] { CloseEvent.class });
  264. } catch (final java.lang.NoSuchMethodException e) {
  265. // This should never happen
  266. throw new java.lang.RuntimeException(
  267. "Internal error, window close method not found");
  268. }
  269. }
  270. public class CloseEvent extends Component.Event {
  271. /**
  272. *
  273. * @param source
  274. */
  275. public CloseEvent(Component source) {
  276. super(source);
  277. }
  278. /**
  279. * Gets the Window.
  280. *
  281. * @return the window.
  282. */
  283. public Window getWindow() {
  284. return (Window) getSource();
  285. }
  286. }
  287. /**
  288. * An interface used for listening to Window close events. Add the
  289. * CloseListener to a browser level window or a sub window and
  290. * {@link CloseListener#windowClose(CloseEvent)} will be called whenever the
  291. * user closes the window.
  292. *
  293. * <p>
  294. * Since Vaadin 6.5, removing a window using {@link #removeWindow(Window)}
  295. * fires the CloseListener.
  296. * </p>
  297. */
  298. public interface CloseListener extends Serializable {
  299. /**
  300. * Called when the user closes a window. Use
  301. * {@link CloseEvent#getWindow()} to get a reference to the
  302. * {@link Window} that was closed.
  303. *
  304. * @param e
  305. * Event containing
  306. */
  307. public void windowClose(CloseEvent e);
  308. }
  309. /**
  310. * Adds a CloseListener to the window.
  311. *
  312. * For a sub window the CloseListener is fired when the user closes it
  313. * (clicks on the close button).
  314. *
  315. * For a browser level window the CloseListener is fired when the browser
  316. * level window is closed. Note that closing a browser level window does not
  317. * mean it will be destroyed. Also note that Opera does not send events like
  318. * all other browsers and therefore the close listener might not be called
  319. * if Opera is used.
  320. *
  321. * <p>
  322. * Since Vaadin 6.5, removing windows using {@link #removeWindow(Window)}
  323. * does fire the CloseListener.
  324. * </p>
  325. *
  326. * @param listener
  327. * the CloseListener to add.
  328. */
  329. public void addListener(CloseListener listener) {
  330. addListener(CloseEvent.class, listener, WINDOW_CLOSE_METHOD);
  331. }
  332. /**
  333. * Removes the CloseListener from the window.
  334. *
  335. * <p>
  336. * For more information on CloseListeners see {@link CloseListener}.
  337. * </p>
  338. *
  339. * @param listener
  340. * the CloseListener to remove.
  341. */
  342. public void removeListener(CloseListener listener) {
  343. removeListener(CloseEvent.class, listener, WINDOW_CLOSE_METHOD);
  344. }
  345. protected void fireClose() {
  346. fireEvent(new Window.CloseEvent(this));
  347. }
  348. /**
  349. * Method for the resize event.
  350. */
  351. private static final Method WINDOW_RESIZE_METHOD;
  352. static {
  353. try {
  354. WINDOW_RESIZE_METHOD = ResizeListener.class.getDeclaredMethod(
  355. "windowResized", new Class[] { ResizeEvent.class });
  356. } catch (final java.lang.NoSuchMethodException e) {
  357. // This should never happen
  358. throw new java.lang.RuntimeException(
  359. "Internal error, window resized method not found");
  360. }
  361. }
  362. /**
  363. * Resize events are fired whenever the client-side fires a resize-event
  364. * (e.g. the browser window is resized). The frequency may vary across
  365. * browsers.
  366. */
  367. public class ResizeEvent extends Component.Event {
  368. /**
  369. *
  370. * @param source
  371. */
  372. public ResizeEvent(Component source) {
  373. super(source);
  374. }
  375. /**
  376. * Get the window form which this event originated
  377. *
  378. * @return the window
  379. */
  380. public Window getWindow() {
  381. return (Window) getSource();
  382. }
  383. }
  384. /**
  385. * Listener for window resize events.
  386. *
  387. * @see com.vaadin.ui.Window.ResizeEvent
  388. */
  389. public interface ResizeListener extends Serializable {
  390. public void windowResized(ResizeEvent e);
  391. }
  392. /**
  393. * Add a resize listener.
  394. *
  395. * @param listener
  396. */
  397. public void addListener(ResizeListener listener) {
  398. addListener(ResizeEvent.class, listener, WINDOW_RESIZE_METHOD);
  399. }
  400. /**
  401. * Remove a resize listener.
  402. *
  403. * @param listener
  404. */
  405. public void removeListener(ResizeListener listener) {
  406. removeListener(ResizeEvent.class, listener);
  407. }
  408. /**
  409. * Fire the resize event.
  410. */
  411. protected void fireResize() {
  412. fireEvent(new ResizeEvent(this));
  413. }
  414. /**
  415. * Used to keep the right order of windows if multiple windows are brought
  416. * to front in a single changeset. If this is not used, the order is quite
  417. * random (depends on the order getting to dirty list. e.g. which window got
  418. * variable changes).
  419. */
  420. private Integer bringToFront = null;
  421. /**
  422. * If there are currently several windows visible, calling this method makes
  423. * this window topmost.
  424. * <p>
  425. * This method can only be called if this window connected a UI. Else an
  426. * illegal state exception is thrown. Also if there are modal windows and
  427. * this window is not modal, and illegal state exception is thrown.
  428. * <p>
  429. */
  430. public void bringToFront() {
  431. UI uI = getUI();
  432. if (uI == null) {
  433. throw new IllegalStateException(
  434. "Window must be attached to parent before calling bringToFront method.");
  435. }
  436. int maxBringToFront = -1;
  437. for (Window w : uI.getWindows()) {
  438. if (!isModal() && w.isModal()) {
  439. throw new IllegalStateException(
  440. "The UI contains modal windows, non-modal window cannot be brought to front.");
  441. }
  442. if (w.bringToFront != null) {
  443. maxBringToFront = Math.max(maxBringToFront,
  444. w.bringToFront.intValue());
  445. }
  446. }
  447. bringToFront = Integer.valueOf(maxBringToFront + 1);
  448. markAsDirty();
  449. }
  450. /**
  451. * Sets sub-window modal, so that widgets behind it cannot be accessed.
  452. * <b>Note:</b> affects sub-windows only.
  453. *
  454. * @param modal
  455. * true if modality is to be turned on
  456. */
  457. public void setModal(boolean modal) {
  458. getState().setModal(modal);
  459. center();
  460. }
  461. /**
  462. * @return true if this window is modal.
  463. */
  464. public boolean isModal() {
  465. return getState().isModal();
  466. }
  467. /**
  468. * Sets sub-window resizable. <b>Note:</b> affects sub-windows only.
  469. *
  470. * @param resizable
  471. * true if resizability is to be turned on
  472. */
  473. public void setResizable(boolean resizable) {
  474. getState().setResizable(resizable);
  475. }
  476. /**
  477. *
  478. * @return true if window is resizable by the end-user, otherwise false.
  479. */
  480. public boolean isResizable() {
  481. return getState().isResizable();
  482. }
  483. /**
  484. *
  485. * @return true if a delay is used before recalculating sizes, false if
  486. * sizes are recalculated immediately.
  487. */
  488. public boolean isResizeLazy() {
  489. return getState().isResizeLazy();
  490. }
  491. /**
  492. * Should resize operations be lazy, i.e. should there be a delay before
  493. * layout sizes are recalculated. Speeds up resize operations in slow UIs
  494. * with the penalty of slightly decreased usability.
  495. *
  496. * Note, some browser send false resize events for the browser window and
  497. * are therefore always lazy.
  498. *
  499. * @param resizeLazy
  500. * true to use a delay before recalculating sizes, false to
  501. * calculate immediately.
  502. */
  503. public void setResizeLazy(boolean resizeLazy) {
  504. getState().setResizeLazy(resizeLazy);
  505. }
  506. /**
  507. * Sets this window to be centered relative to its parent window. Affects
  508. * sub-windows only. If the window is resized as a result of the size of its
  509. * content changing, it will keep itself centered as long as its position is
  510. * not explicitly changed programmatically or by the user.
  511. * <p>
  512. * <b>NOTE:</b> This method has several issues as currently implemented.
  513. * Please refer to http://dev.vaadin.com/ticket/8971 for details.
  514. */
  515. public void center() {
  516. getState().setCentered(true);
  517. }
  518. /**
  519. * Returns the closable status of the sub window. If a sub window is
  520. * closable it typically shows an X in the upper right corner. Clicking on
  521. * the X sends a close event to the server. Setting closable to false will
  522. * remove the X from the sub window and prevent the user from closing the
  523. * window.
  524. *
  525. * Note! For historical reasons readonly controls the closability of the sub
  526. * window and therefore readonly and closable affect each other. Setting
  527. * readonly to true will set closable to false and vice versa.
  528. * <p/>
  529. * Closable only applies to sub windows, not to browser level windows.
  530. *
  531. * @return true if the sub window can be closed by the user.
  532. */
  533. public boolean isClosable() {
  534. return !isReadOnly();
  535. }
  536. /**
  537. * Sets the closable status for the sub window. If a sub window is closable
  538. * it typically shows an X in the upper right corner. Clicking on the X
  539. * sends a close event to the server. Setting closable to false will remove
  540. * the X from the sub window and prevent the user from closing the window.
  541. *
  542. * Note! For historical reasons readonly controls the closability of the sub
  543. * window and therefore readonly and closable affect each other. Setting
  544. * readonly to true will set closable to false and vice versa.
  545. * <p/>
  546. * Closable only applies to sub windows, not to browser level windows.
  547. *
  548. * @param closable
  549. * determines if the sub window can be closed by the user.
  550. */
  551. public void setClosable(boolean closable) {
  552. setReadOnly(!closable);
  553. }
  554. /**
  555. * Indicates whether a sub window can be dragged or not. By default a sub
  556. * window is draggable.
  557. * <p/>
  558. * Draggable only applies to sub windows, not to browser level windows.
  559. *
  560. * @param draggable
  561. * true if the sub window can be dragged by the user
  562. */
  563. public boolean isDraggable() {
  564. return getState().isDraggable();
  565. }
  566. /**
  567. * Enables or disables that a sub window can be dragged (moved) by the user.
  568. * By default a sub window is draggable.
  569. * <p/>
  570. * Draggable only applies to sub windows, not to browser level windows.
  571. *
  572. * @param draggable
  573. * true if the sub window can be dragged by the user
  574. */
  575. public void setDraggable(boolean draggable) {
  576. getState().setDraggable(draggable);
  577. }
  578. /*
  579. * Actions
  580. */
  581. protected CloseShortcut closeShortcut;
  582. /**
  583. * Makes is possible to close the window by pressing the given
  584. * {@link KeyCode} and (optional) {@link ModifierKey}s.<br/>
  585. * Note that this shortcut only reacts while the window has focus, closing
  586. * itself - if you want to close a subwindow from a parent window, use
  587. * {@link #addAction(com.vaadin.event.Action)} of the parent window instead.
  588. *
  589. * @param keyCode
  590. * the keycode for invoking the shortcut
  591. * @param modifiers
  592. * the (optional) modifiers for invoking the shortcut, null for
  593. * none
  594. */
  595. public void setCloseShortcut(int keyCode, int... modifiers) {
  596. if (closeShortcut != null) {
  597. removeAction(closeShortcut);
  598. }
  599. closeShortcut = new CloseShortcut(this, keyCode, modifiers);
  600. addAction(closeShortcut);
  601. }
  602. /**
  603. * Removes the keyboard shortcut previously set with
  604. * {@link #setCloseShortcut(int, int...)}.
  605. */
  606. public void removeCloseShortcut() {
  607. if (closeShortcut != null) {
  608. removeAction(closeShortcut);
  609. closeShortcut = null;
  610. }
  611. }
  612. /**
  613. * A {@link ShortcutListener} specifically made to define a keyboard
  614. * shortcut that closes the window.
  615. *
  616. * <pre>
  617. * <code>
  618. * // within the window using helper
  619. * subWindow.setCloseShortcut(KeyCode.ESCAPE, null);
  620. *
  621. * // or globally
  622. * getWindow().addAction(new Window.CloseShortcut(subWindow, KeyCode.ESCAPE));
  623. * </code>
  624. * </pre>
  625. *
  626. */
  627. public static class CloseShortcut extends ShortcutListener {
  628. protected Window window;
  629. /**
  630. * Creates a keyboard shortcut for closing the given window using the
  631. * shorthand notation defined in {@link ShortcutAction}.
  632. *
  633. * @param window
  634. * to be closed when the shortcut is invoked
  635. * @param shorthandCaption
  636. * the caption with shortcut keycode and modifiers indicated
  637. */
  638. public CloseShortcut(Window window, String shorthandCaption) {
  639. super(shorthandCaption);
  640. this.window = window;
  641. }
  642. /**
  643. * Creates a keyboard shortcut for closing the given window using the
  644. * given {@link KeyCode} and {@link ModifierKey}s.
  645. *
  646. * @param window
  647. * to be closed when the shortcut is invoked
  648. * @param keyCode
  649. * KeyCode to react to
  650. * @param modifiers
  651. * optional modifiers for shortcut
  652. */
  653. public CloseShortcut(Window window, int keyCode, int... modifiers) {
  654. super(null, keyCode, modifiers);
  655. this.window = window;
  656. }
  657. /**
  658. * Creates a keyboard shortcut for closing the given window using the
  659. * given {@link KeyCode}.
  660. *
  661. * @param window
  662. * to be closed when the shortcut is invoked
  663. * @param keyCode
  664. * KeyCode to react to
  665. */
  666. public CloseShortcut(Window window, int keyCode) {
  667. this(window, keyCode, null);
  668. }
  669. @Override
  670. public void handleAction(Object sender, Object target) {
  671. window.close();
  672. }
  673. }
  674. /**
  675. * Note, that focus/blur listeners in Window class are only supported by sub
  676. * windows. Also note that Window is not considered focused if its contained
  677. * component currently has focus.
  678. *
  679. * @see com.vaadin.event.FieldEvents.FocusNotifier#addListener(com.vaadin.event.FieldEvents.FocusListener)
  680. */
  681. @Override
  682. public void addListener(FocusListener listener) {
  683. addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
  684. FocusListener.focusMethod);
  685. }
  686. @Override
  687. public void removeListener(FocusListener listener) {
  688. removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
  689. }
  690. /**
  691. * Note, that focus/blur listeners in Window class are only supported by sub
  692. * windows. Also note that Window is not considered focused if its contained
  693. * component currently has focus.
  694. *
  695. * @see com.vaadin.event.FieldEvents.BlurNotifier#addListener(com.vaadin.event.FieldEvents.BlurListener)
  696. */
  697. @Override
  698. public void addListener(BlurListener listener) {
  699. addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
  700. BlurListener.blurMethod);
  701. }
  702. @Override
  703. public void removeListener(BlurListener listener) {
  704. removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
  705. }
  706. /**
  707. * {@inheritDoc}
  708. *
  709. * If the window is a sub-window focusing will cause the sub-window to be
  710. * brought on top of other sub-windows on gain keyboard focus.
  711. */
  712. @Override
  713. public void focus() {
  714. /*
  715. * When focusing a sub-window it basically means it should be brought to
  716. * the front. Instead of just moving the keyboard focus we focus the
  717. * window and bring it top-most.
  718. */
  719. super.focus();
  720. bringToFront();
  721. }
  722. @Override
  723. protected WindowState getState() {
  724. return (WindowState) super.getState();
  725. }
  726. }