Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

Window.java 28KB

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