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

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553
  1. /*
  2. * Copyright 2000-2016 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.ui;
  17. import java.io.Serializable;
  18. import java.lang.reflect.Method;
  19. import java.util.ArrayList;
  20. import java.util.Arrays;
  21. import java.util.Collection;
  22. import java.util.Collections;
  23. import java.util.List;
  24. import java.util.Map;
  25. import org.jsoup.nodes.Element;
  26. import org.jsoup.select.Elements;
  27. import com.vaadin.event.ConnectorEventListener;
  28. import com.vaadin.event.FieldEvents.BlurEvent;
  29. import com.vaadin.event.FieldEvents.BlurListener;
  30. import com.vaadin.event.FieldEvents.BlurNotifier;
  31. import com.vaadin.event.FieldEvents.FocusEvent;
  32. import com.vaadin.event.FieldEvents.FocusListener;
  33. import com.vaadin.event.FieldEvents.FocusNotifier;
  34. import com.vaadin.event.MouseEvents.ClickEvent;
  35. import com.vaadin.event.ShortcutAction;
  36. import com.vaadin.event.ShortcutAction.KeyCode;
  37. import com.vaadin.event.ShortcutAction.ModifierKey;
  38. import com.vaadin.event.ShortcutListener;
  39. import com.vaadin.server.PaintException;
  40. import com.vaadin.server.PaintTarget;
  41. import com.vaadin.shared.Connector;
  42. import com.vaadin.shared.EventId;
  43. import com.vaadin.shared.MouseEventDetails;
  44. import com.vaadin.shared.Registration;
  45. import com.vaadin.shared.ui.window.WindowMode;
  46. import com.vaadin.shared.ui.window.WindowRole;
  47. import com.vaadin.shared.ui.window.WindowServerRpc;
  48. import com.vaadin.shared.ui.window.WindowState;
  49. import com.vaadin.ui.declarative.DesignAttributeHandler;
  50. import com.vaadin.ui.declarative.DesignContext;
  51. import com.vaadin.ui.declarative.DesignException;
  52. import com.vaadin.util.ReflectTools;
  53. /**
  54. * A component that represents a floating popup window that can be added to a
  55. * {@link UI}. A window is added to a {@code UI} using
  56. * {@link UI#addWindow(Window)}.
  57. * </p>
  58. * <p>
  59. * The contents of a window is set using {@link #setContent(Component)} or by
  60. * using the {@link #Window(String, Component)} constructor.
  61. * </p>
  62. * <p>
  63. * A window can be positioned on the screen using absolute coordinates (pixels)
  64. * or set to be centered using {@link #center()}
  65. * </p>
  66. * <p>
  67. * The caption is displayed in the window header.
  68. * </p>
  69. * <p>
  70. * In Vaadin versions prior to 7.0.0, Window was also used as application level
  71. * windows. This function is now covered by the {@link UI} class.
  72. * </p>
  73. *
  74. * @author Vaadin Ltd.
  75. * @since 3.0
  76. */
  77. @SuppressWarnings({ "serial", "deprecation" })
  78. public class Window extends Panel
  79. implements FocusNotifier, BlurNotifier, LegacyComponent {
  80. private WindowServerRpc rpc = new WindowServerRpc() {
  81. @Override
  82. public void click(MouseEventDetails mouseDetails) {
  83. fireEvent(new ClickEvent(Window.this, mouseDetails));
  84. }
  85. @Override
  86. public void windowModeChanged(WindowMode newState) {
  87. setWindowMode(newState);
  88. }
  89. @Override
  90. public void windowMoved(int x, int y) {
  91. if (x != getState(false).positionX) {
  92. setPositionX(x);
  93. }
  94. if (y != getState(false).positionY) {
  95. setPositionY(y);
  96. }
  97. }
  98. };
  99. /**
  100. * Holds registered CloseShortcut instances for query and later removal
  101. */
  102. private List<CloseShortcut> closeShortcuts = new ArrayList<>(4);
  103. /**
  104. * Used to keep the window order position. Order position for unattached
  105. * window is {@code -1}.
  106. * <p>
  107. * Window with greatest order position value is on the top and window with 0
  108. * position value is on the bottom.
  109. */
  110. private int orderPosition = -1;
  111. /**
  112. * Creates a new, empty window
  113. */
  114. public Window() {
  115. this("", null);
  116. }
  117. /**
  118. * Creates a new, empty window with a given title.
  119. *
  120. * @param caption
  121. * the title of the window.
  122. */
  123. public Window(String caption) {
  124. this(caption, null);
  125. }
  126. /**
  127. * Creates a new, empty window with the given content and title.
  128. *
  129. * @param caption
  130. * the title of the window.
  131. * @param content
  132. * the contents of the window
  133. */
  134. public Window(String caption, Component content) {
  135. super(caption, content);
  136. registerRpc(rpc);
  137. setSizeUndefined();
  138. setCloseShortcut(KeyCode.ESCAPE);
  139. }
  140. /* ********************************************************************* */
  141. /*
  142. * (non-Javadoc)
  143. *
  144. * @see com.vaadin.ui.Panel#paintContent(com.vaadin.server.PaintTarget)
  145. */
  146. @Override
  147. public synchronized void paintContent(PaintTarget target)
  148. throws PaintException {
  149. if (bringToFront != null) {
  150. target.addAttribute("bringToFront", bringToFront.intValue());
  151. bringToFront = null;
  152. }
  153. // Contents of the window panel is painted
  154. super.paintContent(target);
  155. }
  156. /*
  157. * (non-Javadoc)
  158. *
  159. * @see com.vaadin.ui.AbstractComponent#setParent(com.vaadin.server.
  160. * ClientConnector )
  161. */
  162. @Override
  163. public void setParent(HasComponents parent) {
  164. if (parent == null || parent instanceof UI) {
  165. super.setParent(parent);
  166. } else {
  167. throw new IllegalArgumentException(
  168. "A Window can only be added to a UI using UI.addWindow(Window window)");
  169. }
  170. }
  171. /*
  172. * (non-Javadoc)
  173. *
  174. * @see com.vaadin.ui.Panel#changeVariables(java.lang.Object, java.util.Map)
  175. */
  176. @Override
  177. public void changeVariables(Object source, Map<String, Object> variables) {
  178. // TODO Are these for top level windows or sub windows?
  179. boolean sizeHasChanged = false;
  180. // size is handled in super class, but resize events only in windows ->
  181. // so detect if size change occurs before super.changeVariables()
  182. if (variables.containsKey("height") && (getHeightUnits() != Unit.PIXELS
  183. || (Integer) variables.get("height") != getHeight())) {
  184. sizeHasChanged = true;
  185. }
  186. if (variables.containsKey("width") && (getWidthUnits() != Unit.PIXELS
  187. || (Integer) variables.get("width") != getWidth())) {
  188. sizeHasChanged = true;
  189. }
  190. super.changeVariables(source, variables);
  191. // Positioning
  192. final Integer positionx = (Integer) variables.get("positionx");
  193. if (positionx != null) {
  194. final int x = positionx.intValue();
  195. // This is information from the client so it is already using the
  196. // position. No need to repaint.
  197. setPositionX(x < 0 ? -1 : x);
  198. }
  199. final Integer positiony = (Integer) variables.get("positiony");
  200. if (positiony != null) {
  201. final int y = positiony.intValue();
  202. // This is information from the client so it is already using the
  203. // position. No need to repaint.
  204. setPositionY(y < 0 ? -1 : y);
  205. }
  206. if (isClosable()) {
  207. // Closing
  208. final Boolean close = (Boolean) variables.get("close");
  209. if (close != null && close.booleanValue()) {
  210. close();
  211. }
  212. }
  213. // fire event if size has really changed
  214. if (sizeHasChanged) {
  215. fireResize();
  216. }
  217. if (variables.containsKey(FocusEvent.EVENT_ID)) {
  218. fireEvent(new FocusEvent(this));
  219. } else if (variables.containsKey(BlurEvent.EVENT_ID)) {
  220. fireEvent(new BlurEvent(this));
  221. }
  222. }
  223. /**
  224. * Method that handles window closing (from UI).
  225. *
  226. * <p>
  227. * By default, windows are removed from their respective UIs and thus
  228. * visually closed on browser-side.
  229. * </p>
  230. *
  231. * <p>
  232. * To react to a window being closed (after it is closed), register a
  233. * {@link CloseListener}.
  234. * </p>
  235. */
  236. public void close() {
  237. UI uI = getUI();
  238. // Don't do anything if not attached to a UI
  239. if (uI != null) {
  240. // window is removed from the UI
  241. uI.removeWindow(this);
  242. }
  243. }
  244. /**
  245. * Gets the distance of Window left border in pixels from left border of the
  246. * containing (main window) when the window is in {@link WindowMode#NORMAL}.
  247. *
  248. * @return the Distance of Window left border in pixels from left border of
  249. * the containing (main window).or -1 if unspecified
  250. * @since 4.0.0
  251. */
  252. public int getPositionX() {
  253. return getState(false).positionX;
  254. }
  255. /**
  256. * Sets the position of the window on the screen using
  257. * {@link #setPositionX(int)} and {@link #setPositionY(int)}
  258. *
  259. * @since 7.5
  260. * @param x
  261. * The new x coordinate for the window
  262. * @param y
  263. * The new y coordinate for the window
  264. */
  265. public void setPosition(int x, int y) {
  266. setPositionX(x);
  267. setPositionY(y);
  268. }
  269. /**
  270. * Sets the distance of Window left border in pixels from left border of the
  271. * containing (main window). Has effect only if in {@link WindowMode#NORMAL}
  272. * mode.
  273. *
  274. * @param positionX
  275. * the Distance of Window left border in pixels from left border
  276. * of the containing (main window). or -1 if unspecified.
  277. * @since 4.0.0
  278. */
  279. public void setPositionX(int positionX) {
  280. getState().positionX = positionX;
  281. getState().centered = false;
  282. }
  283. /**
  284. * Gets the distance of Window top border in pixels from top border of the
  285. * containing (main window) when the window is in {@link WindowMode#NORMAL}
  286. * state, or when next set to that state.
  287. *
  288. * @return Distance of Window top border in pixels from top border of the
  289. * containing (main window). or -1 if unspecified
  290. *
  291. * @since 4.0.0
  292. */
  293. public int getPositionY() {
  294. return getState(false).positionY;
  295. }
  296. /**
  297. * Returns the position of this window in the order of all open windows for
  298. * this UI.
  299. * <p>
  300. * Window with position 0 is on the bottom, and window with greatest
  301. * position is at the top. If window has no position (it's not yet attached
  302. * or hidden) then position is {@code -1}.
  303. *
  304. * @see UI#addWindowOrderUpdateListener(com.vaadin.ui.UI.WindowOrderUpdateListener)
  305. *
  306. * @since 8.0.0
  307. *
  308. * @return window order position.
  309. */
  310. public int getOrderPosition() {
  311. return orderPosition;
  312. }
  313. /**
  314. * Sets the distance of Window top border in pixels from top border of the
  315. * containing (main window). Has effect only if in {@link WindowMode#NORMAL}
  316. * mode.
  317. *
  318. * @param positionY
  319. * the Distance of Window top border in pixels from top border of
  320. * the containing (main window). or -1 if unspecified
  321. *
  322. * @since 4.0.0
  323. */
  324. public void setPositionY(int positionY) {
  325. getState().positionY = positionY;
  326. getState().centered = false;
  327. }
  328. private static final Method WINDOW_CLOSE_METHOD;
  329. static {
  330. try {
  331. WINDOW_CLOSE_METHOD = CloseListener.class
  332. .getDeclaredMethod("windowClose", CloseEvent.class);
  333. } catch (final java.lang.NoSuchMethodException e) {
  334. // This should never happen
  335. throw new java.lang.RuntimeException(
  336. "Internal error, window close method not found");
  337. }
  338. }
  339. public static class CloseEvent extends Component.Event {
  340. /**
  341. *
  342. * @param source
  343. */
  344. public CloseEvent(Component source) {
  345. super(source);
  346. }
  347. /**
  348. * Gets the Window.
  349. *
  350. * @return the window.
  351. */
  352. public Window getWindow() {
  353. return (Window) getSource();
  354. }
  355. }
  356. /**
  357. * Event which is fired when the window order position is changed.
  358. *
  359. * @see UI.WindowOrderUpdateEvent
  360. *
  361. * @author Vaadin Ltd
  362. *
  363. */
  364. public static class WindowOrderChangeEvent extends Component.Event {
  365. private final int order;
  366. public WindowOrderChangeEvent(Component source, int order) {
  367. super(source);
  368. this.order = order;
  369. }
  370. /**
  371. * Gets the Window.
  372. *
  373. * @return the window
  374. */
  375. public Window getWindow() {
  376. return (Window) getSource();
  377. }
  378. /**
  379. * Gets the new window order position.
  380. *
  381. * @return the new order position
  382. */
  383. public int getOrder() {
  384. return order;
  385. }
  386. }
  387. /**
  388. * An interface used for listening to Window order change events.
  389. *
  390. * @see UI.WindowOrderUpdateListener
  391. */
  392. public interface WindowOrderChangeListener extends ConnectorEventListener {
  393. public static final Method windowOrderChangeMethod = ReflectTools
  394. .findMethod(WindowOrderChangeListener.class,
  395. "windowOrderChanged", WindowOrderChangeEvent.class);
  396. /**
  397. * Called when the window order position is changed. Use
  398. * {@link WindowOrderChangeEvent#getWindow()} to get a reference to the
  399. * {@link Window} whose order position is changed. Use
  400. * {@link WindowOrderChangeEvent#getOrder()} to get a new order
  401. * position.
  402. *
  403. * @param event
  404. */
  405. public void windowOrderChanged(WindowOrderChangeEvent event);
  406. }
  407. /**
  408. * Adds a WindowOrderChangeListener to the window.
  409. * <p>
  410. * The WindowOrderChangeEvent is fired when the order position is changed.
  411. * It can happen when some window (this or other) is brought to front or
  412. * detached.
  413. * <p>
  414. * The other way to listen positions of all windows in UI is
  415. * {@link UI#addWindowOrderUpdateListener(com.vaadin.ui.UI.WindowOrderUpdateListener)}
  416. *
  417. * @see UI#addWindowOrderUpdateListener(com.vaadin.ui.UI.WindowOrderUpdateListener)
  418. *
  419. * @param listener
  420. * the WindowModeChangeListener to add.
  421. */
  422. public Registration addWindowOrderChangeListener(
  423. WindowOrderChangeListener listener) {
  424. addListener(EventId.WINDOW_ORDER, WindowOrderChangeEvent.class,
  425. listener, WindowOrderChangeListener.windowOrderChangeMethod);
  426. return () -> removeListener(EventId.WINDOW_ORDER,
  427. WindowOrderChangeEvent.class, listener);
  428. }
  429. protected void fireWindowOrderChange(Integer order) {
  430. if (order == null || this.orderPosition != order) {
  431. this.orderPosition = (order == null) ? -1 : order;
  432. fireEvent(new Window.WindowOrderChangeEvent(this,
  433. getOrderPosition()));
  434. }
  435. }
  436. /**
  437. * An interface used for listening to Window close events. Add the
  438. * CloseListener to a window and
  439. * {@link CloseListener#windowClose(CloseEvent)} will be called whenever the
  440. * user closes the window.
  441. *
  442. * <p>
  443. * Since Vaadin 6.5, removing a window using {@link #removeWindow(Window)}
  444. * fires the CloseListener.
  445. * </p>
  446. */
  447. public interface CloseListener extends Serializable {
  448. /**
  449. * Called when the user closes a window. Use
  450. * {@link CloseEvent#getWindow()} to get a reference to the
  451. * {@link Window} that was closed.
  452. *
  453. * @param e
  454. * Event containing
  455. */
  456. public void windowClose(CloseEvent e);
  457. }
  458. /**
  459. * Adds a CloseListener to the window.
  460. *
  461. * For a window the CloseListener is fired when the user closes it (clicks
  462. * on the close button).
  463. *
  464. * For a browser level window the CloseListener is fired when the browser
  465. * level window is closed. Note that closing a browser level window does not
  466. * mean it will be destroyed. Also note that Opera does not send events like
  467. * all other browsers and therefore the close listener might not be called
  468. * if Opera is used.
  469. *
  470. * <p>
  471. * Since Vaadin 6.5, removing windows using {@link #removeWindow(Window)}
  472. * does fire the CloseListener.
  473. * </p>
  474. *
  475. * @param listener
  476. * the CloseListener to add, not null
  477. */
  478. public Registration addCloseListener(CloseListener listener) {
  479. return addListener(CloseEvent.class, listener, WINDOW_CLOSE_METHOD);
  480. }
  481. /**
  482. * Removes the CloseListener from the window.
  483. *
  484. * <p>
  485. * For more information on CloseListeners see {@link CloseListener}.
  486. * </p>
  487. *
  488. * @param listener
  489. * the CloseListener to remove.
  490. */
  491. @Deprecated
  492. public void removeCloseListener(CloseListener listener) {
  493. removeListener(CloseEvent.class, listener, WINDOW_CLOSE_METHOD);
  494. }
  495. protected void fireClose() {
  496. fireEvent(new Window.CloseEvent(this));
  497. }
  498. /**
  499. * Event which is fired when the mode of the Window changes.
  500. *
  501. * @author Vaadin Ltd
  502. * @since 7.1
  503. *
  504. */
  505. public static class WindowModeChangeEvent extends Component.Event {
  506. private final WindowMode windowMode;
  507. /**
  508. *
  509. * @param source
  510. */
  511. public WindowModeChangeEvent(Component source, WindowMode windowMode) {
  512. super(source);
  513. this.windowMode = windowMode;
  514. }
  515. /**
  516. * Gets the Window.
  517. *
  518. * @return the window
  519. */
  520. public Window getWindow() {
  521. return (Window) getSource();
  522. }
  523. /**
  524. * Gets the new window mode.
  525. *
  526. * @return the new mode
  527. */
  528. public WindowMode getWindowMode() {
  529. return windowMode;
  530. }
  531. }
  532. /**
  533. * An interface used for listening to Window maximize / restore events. Add
  534. * the WindowModeChangeListener to a window and
  535. * {@link WindowModeChangeListener#windowModeChanged(WindowModeChangeEvent)}
  536. * will be called whenever the window is maximized (
  537. * {@link WindowMode#MAXIMIZED}) or restored ({@link WindowMode#NORMAL} ).
  538. */
  539. public interface WindowModeChangeListener extends Serializable {
  540. public static final Method windowModeChangeMethod = ReflectTools
  541. .findMethod(WindowModeChangeListener.class, "windowModeChanged",
  542. WindowModeChangeEvent.class);
  543. /**
  544. * Called when the user maximizes / restores a window. Use
  545. * {@link WindowModeChangeEvent#getWindow()} to get a reference to the
  546. * {@link Window} that was maximized / restored. Use
  547. * {@link WindowModeChangeEvent#getWindowMode()} to get a reference to
  548. * the new state.
  549. *
  550. * @param event
  551. */
  552. public void windowModeChanged(WindowModeChangeEvent event);
  553. }
  554. /**
  555. * Adds a WindowModeChangeListener to the window.
  556. *
  557. * The WindowModeChangeEvent is fired when the user changed the display
  558. * state by clicking the maximize/restore button or by double clicking on
  559. * the window header. The event is also fired if the state is changed using
  560. * {@link #setWindowMode(WindowMode)}.
  561. *
  562. * @param listener
  563. * the WindowModeChangeListener to add.
  564. */
  565. public Registration addWindowModeChangeListener(
  566. WindowModeChangeListener listener) {
  567. return addListener(WindowModeChangeEvent.class, listener,
  568. WindowModeChangeListener.windowModeChangeMethod);
  569. }
  570. /**
  571. * Removes the WindowModeChangeListener from the window.
  572. *
  573. * @param listener
  574. * the WindowModeChangeListener to remove.
  575. */
  576. @Deprecated
  577. public void removeWindowModeChangeListener(
  578. WindowModeChangeListener listener) {
  579. removeListener(WindowModeChangeEvent.class, listener,
  580. WindowModeChangeListener.windowModeChangeMethod);
  581. }
  582. protected void fireWindowWindowModeChange() {
  583. fireEvent(
  584. new Window.WindowModeChangeEvent(this, getState().windowMode));
  585. }
  586. /**
  587. * Method for the resize event.
  588. */
  589. private static final Method WINDOW_RESIZE_METHOD;
  590. static {
  591. try {
  592. WINDOW_RESIZE_METHOD = ResizeListener.class
  593. .getDeclaredMethod("windowResized", ResizeEvent.class);
  594. } catch (final java.lang.NoSuchMethodException e) {
  595. // This should never happen
  596. throw new java.lang.RuntimeException(
  597. "Internal error, window resized method not found");
  598. }
  599. }
  600. /**
  601. * Resize events are fired whenever the client-side fires a resize-event
  602. * (e.g. the browser window is resized). The frequency may vary across
  603. * browsers.
  604. */
  605. public static class ResizeEvent extends Component.Event {
  606. /**
  607. *
  608. * @param source
  609. */
  610. public ResizeEvent(Component source) {
  611. super(source);
  612. }
  613. /**
  614. * Get the window form which this event originated
  615. *
  616. * @return the window
  617. */
  618. public Window getWindow() {
  619. return (Window) getSource();
  620. }
  621. }
  622. /**
  623. * Listener for window resize events.
  624. *
  625. * @see com.vaadin.ui.Window.ResizeEvent
  626. */
  627. public interface ResizeListener extends Serializable {
  628. public void windowResized(ResizeEvent e);
  629. }
  630. /**
  631. * Add a resize listener.
  632. *
  633. * @see Registration
  634. *
  635. * @param listener
  636. * the listener to add, not null
  637. * @return a registration object for removing the listener
  638. */
  639. public Registration addResizeListener(ResizeListener listener) {
  640. return addListener(ResizeEvent.class, listener, WINDOW_RESIZE_METHOD);
  641. }
  642. /**
  643. * Remove a resize listener.
  644. *
  645. * @param listener
  646. */
  647. @Deprecated
  648. public void removeResizeListener(ResizeListener listener) {
  649. removeListener(ResizeEvent.class, listener);
  650. }
  651. /**
  652. * Fire the resize event.
  653. */
  654. protected void fireResize() {
  655. fireEvent(new ResizeEvent(this));
  656. }
  657. /**
  658. * Used to keep the right order of windows if multiple windows are brought
  659. * to front in a single changeset. If this is not used, the order is quite
  660. * random (depends on the order getting to dirty list. e.g. which window got
  661. * variable changes).
  662. */
  663. private Integer bringToFront = null;
  664. /**
  665. * If there are currently several windows visible, calling this method makes
  666. * this window topmost.
  667. * <p>
  668. * This method can only be called if this window connected a UI. Else an
  669. * illegal state exception is thrown. Also if there are modal windows and
  670. * this window is not modal, and illegal state exception is thrown.
  671. * <p>
  672. */
  673. public void bringToFront() {
  674. UI uI = getUI();
  675. if (uI == null) {
  676. throw new IllegalStateException(
  677. "Window must be attached to parent before calling bringToFront method.");
  678. }
  679. int maxBringToFront = -1;
  680. for (Window w : uI.getWindows()) {
  681. if (!isModal() && w.isModal()) {
  682. throw new IllegalStateException(
  683. "The UI contains modal windows, non-modal window cannot be brought to front.");
  684. }
  685. if (w.bringToFront != null) {
  686. maxBringToFront = Math.max(maxBringToFront,
  687. w.bringToFront.intValue());
  688. }
  689. }
  690. bringToFront = Integer.valueOf(maxBringToFront + 1);
  691. markAsDirty();
  692. }
  693. /**
  694. * Sets window modality. When a modal window is open, components outside
  695. * that window cannot be accessed.
  696. * <p>
  697. * Keyboard navigation is restricted by blocking the tab key at the top and
  698. * bottom of the window by activating the tab stop function internally.
  699. *
  700. * @param modal
  701. * true if modality is to be turned on
  702. */
  703. public void setModal(boolean modal) {
  704. getState().modal = modal;
  705. center();
  706. }
  707. /**
  708. * @return true if this window is modal.
  709. */
  710. public boolean isModal() {
  711. return getState(false).modal;
  712. }
  713. /**
  714. * Sets window resizable.
  715. *
  716. * @param resizable
  717. * true if resizability is to be turned on
  718. */
  719. public void setResizable(boolean resizable) {
  720. getState().resizable = resizable;
  721. }
  722. /**
  723. *
  724. * @return true if window is resizable by the end-user, otherwise false.
  725. */
  726. public boolean isResizable() {
  727. return getState(false).resizable;
  728. }
  729. /**
  730. *
  731. * @return true if a delay is used before recalculating sizes, false if
  732. * sizes are recalculated immediately.
  733. */
  734. public boolean isResizeLazy() {
  735. return getState(false).resizeLazy;
  736. }
  737. /**
  738. * Should resize operations be lazy, i.e. should there be a delay before
  739. * layout sizes are recalculated. Speeds up resize operations in slow UIs
  740. * with the penalty of slightly decreased usability.
  741. *
  742. * Note, some browser send false resize events for the browser window and
  743. * are therefore always lazy.
  744. *
  745. * @param resizeLazy
  746. * true to use a delay before recalculating sizes, false to
  747. * calculate immediately.
  748. */
  749. public void setResizeLazy(boolean resizeLazy) {
  750. getState().resizeLazy = resizeLazy;
  751. }
  752. /**
  753. * Sets this window to be centered relative to its parent window. Affects
  754. * windows only. If the window is resized as a result of the size of its
  755. * content changing, it will keep itself centered as long as its position is
  756. * not explicitly changed programmatically or by the user.
  757. * <p>
  758. * <b>NOTE:</b> This method has several issues as currently implemented.
  759. * Please refer to http://dev.vaadin.com/ticket/8971 for details.
  760. */
  761. public void center() {
  762. getState().centered = true;
  763. }
  764. /**
  765. * Returns the closable status of the window. If a window is closable, it
  766. * typically shows an X in the upper right corner. Clicking on the X sends a
  767. * close event to the server. Setting closable to false will remove the X
  768. * from the window and prevent the user from closing the window.
  769. *
  770. * @return true if the window can be closed by the user.
  771. */
  772. public boolean isClosable() {
  773. return getState(false).closable;
  774. }
  775. /**
  776. * Sets the closable status for the window. If a window is closable it
  777. * typically shows an X in the upper right corner. Clicking on the X sends a
  778. * close event to the server. Setting closable to false will remove the X
  779. * from the window and prevent the user from closing the window.
  780. *
  781. * @param closable
  782. * determines if the window can be closed by the user.
  783. */
  784. public void setClosable(boolean closable) {
  785. if (closable != isClosable()) {
  786. getState().closable = closable;
  787. }
  788. }
  789. /**
  790. * Indicates whether a window can be dragged or not. By default a window is
  791. * draggable.
  792. *
  793. * @return {@code true} if window is draggable; {@code false} if not
  794. */
  795. public boolean isDraggable() {
  796. return getState(false).draggable;
  797. }
  798. /**
  799. * Enables or disables that a window can be dragged (moved) by the user. By
  800. * default a window is draggable.
  801. * <p/>
  802. *
  803. * @param draggable
  804. * true if the window can be dragged by the user
  805. */
  806. public void setDraggable(boolean draggable) {
  807. getState().draggable = draggable;
  808. }
  809. /**
  810. * Gets the current mode of the window.
  811. *
  812. * @see WindowMode
  813. * @return the mode of the window.
  814. */
  815. public WindowMode getWindowMode() {
  816. return getState(false).windowMode;
  817. }
  818. /**
  819. * Sets the mode for the window
  820. *
  821. * @see WindowMode
  822. * @param windowMode
  823. * The new mode
  824. */
  825. public void setWindowMode(WindowMode windowMode) {
  826. if (windowMode != getWindowMode()) {
  827. getState().windowMode = windowMode;
  828. fireWindowWindowModeChange();
  829. }
  830. }
  831. /**
  832. * This is the old way of adding a keyboard shortcut to close a
  833. * {@link Window} - to preserve compatibility with existing code under the
  834. * new functionality, this method now first removes all registered close
  835. * shortcuts, then adds the default ESCAPE shortcut key, and then attempts
  836. * to add the shortcut provided as parameters to this method. This method,
  837. * and its companion {@link #removeCloseShortcut()}, are now considered
  838. * deprecated, as their main function is to preserve exact backwards
  839. * compatibility with old code. For all new code, use the new keyboard
  840. * shortcuts API: {@link #addCloseShortcut(int,int...)},
  841. * {@link #removeCloseShortcut(int,int...)},
  842. * {@link #removeAllCloseShortcuts()}, {@link #hasCloseShortcut(int,int...)}
  843. * and {@link #getCloseShortcuts()}.
  844. * <p>
  845. * Original description: Makes it possible to close the window by pressing
  846. * the given {@link KeyCode} and (optional) {@link ModifierKey}s.<br/>
  847. * Note that this shortcut only reacts while the window has focus, closing
  848. * itself - if you want to close a window from a UI, use
  849. * {@link UI#addAction(com.vaadin.event.Action)} of the UI instead.
  850. *
  851. * @param keyCode
  852. * the keycode for invoking the shortcut
  853. * @param modifiers
  854. * the (optional) modifiers for invoking the shortcut. Can be set
  855. * to null to be explicit about not having modifiers.
  856. *
  857. * @deprecated Use {@link #addCloseShortcut(int, int...)} instead.
  858. */
  859. @Deprecated
  860. public void setCloseShortcut(int keyCode, int... modifiers) {
  861. removeCloseShortcut();
  862. addCloseShortcut(keyCode, modifiers);
  863. }
  864. /**
  865. * Removes all keyboard shortcuts previously set with
  866. * {@link #setCloseShortcut(int, int...)} and
  867. * {@link #addCloseShortcut(int, int...)}, then adds the default
  868. * {@link KeyCode#ESCAPE} shortcut.
  869. * <p>
  870. * This is the old way of removing the (single) keyboard close shortcut, and
  871. * is retained only for exact backwards compatibility. For all new code, use
  872. * the new keyboard shortcuts API: {@link #addCloseShortcut(int,int...)},
  873. * {@link #removeCloseShortcut(int,int...)},
  874. * {@link #removeAllCloseShortcuts()}, {@link #hasCloseShortcut(int,int...)}
  875. * and {@link #getCloseShortcuts()}.
  876. *
  877. * @deprecated Use {@link #removeCloseShortcut(int, int...)} instead.
  878. */
  879. @Deprecated
  880. public void removeCloseShortcut() {
  881. for (CloseShortcut sc : closeShortcuts) {
  882. removeAction(sc);
  883. }
  884. closeShortcuts.clear();
  885. addCloseShortcut(KeyCode.ESCAPE);
  886. }
  887. /**
  888. * Adds a close shortcut - pressing this key while holding down all (if any)
  889. * modifiers specified while this Window is in focus will close the Window.
  890. *
  891. * @since 7.6
  892. * @param keyCode
  893. * the keycode for invoking the shortcut
  894. * @param modifiers
  895. * the (optional) modifiers for invoking the shortcut. Can be set
  896. * to null to be explicit about not having modifiers.
  897. */
  898. public void addCloseShortcut(int keyCode, int... modifiers) {
  899. // Ignore attempts to re-add existing shortcuts
  900. if (hasCloseShortcut(keyCode, modifiers)) {
  901. return;
  902. }
  903. // Actually add the shortcut
  904. CloseShortcut shortcut = new CloseShortcut(this, keyCode, modifiers);
  905. addAction(shortcut);
  906. closeShortcuts.add(shortcut);
  907. }
  908. /**
  909. * Removes a close shortcut previously added with
  910. * {@link #addCloseShortcut(int, int...)}.
  911. *
  912. * @since 7.6
  913. * @param keyCode
  914. * the keycode for invoking the shortcut
  915. * @param modifiers
  916. * the (optional) modifiers for invoking the shortcut. Can be set
  917. * to null to be explicit about not having modifiers.
  918. */
  919. public void removeCloseShortcut(int keyCode, int... modifiers) {
  920. for (CloseShortcut shortcut : closeShortcuts) {
  921. if (shortcut.equals(keyCode, modifiers)) {
  922. removeAction(shortcut);
  923. closeShortcuts.remove(shortcut);
  924. return;
  925. }
  926. }
  927. }
  928. /**
  929. * Removes all close shortcuts. This includes the default ESCAPE shortcut.
  930. * It is up to the user to add back any and all keyboard close shortcuts
  931. * they may require. For more fine-grained control over shortcuts, use
  932. * {@link #removeCloseShortcut(int, int...)}.
  933. *
  934. * @since 7.6
  935. */
  936. public void removeAllCloseShortcuts() {
  937. for (CloseShortcut shortcut : closeShortcuts) {
  938. removeAction(shortcut);
  939. }
  940. closeShortcuts.clear();
  941. }
  942. /**
  943. * Checks if a close window shortcut key has already been registered.
  944. *
  945. * @since 7.6
  946. * @param keyCode
  947. * the keycode for invoking the shortcut
  948. * @param modifiers
  949. * the (optional) modifiers for invoking the shortcut. Can be set
  950. * to null to be explicit about not having modifiers.
  951. * @return true, if an exactly matching shortcut has been registered.
  952. */
  953. public boolean hasCloseShortcut(int keyCode, int... modifiers) {
  954. for (CloseShortcut shortcut : closeShortcuts) {
  955. if (shortcut.equals(keyCode, modifiers)) {
  956. return true;
  957. }
  958. }
  959. return false;
  960. }
  961. /**
  962. * Returns an unmodifiable collection of {@link CloseShortcut} objects
  963. * currently registered with this {@link Window}. This method is provided
  964. * mainly so that users can implement their own serialization routines. To
  965. * check if a certain combination of keys has been registered as a close
  966. * shortcut, use the {@link #hasCloseShortcut(int, int...)} method instead.
  967. *
  968. * @since 7.6
  969. * @return an unmodifiable Collection of CloseShortcut objects.
  970. */
  971. public Collection<CloseShortcut> getCloseShortcuts() {
  972. return Collections.unmodifiableCollection(closeShortcuts);
  973. }
  974. /**
  975. * A {@link ShortcutListener} specifically made to define a keyboard
  976. * shortcut that closes the window.
  977. *
  978. * <pre>
  979. * <code>
  980. * // within the window using helper
  981. * window.setCloseShortcut(KeyCode.ESCAPE, null);
  982. *
  983. * // or globally
  984. * getUI().addAction(new Window.CloseShortcut(window, KeyCode.ESCAPE));
  985. * </code>
  986. * </pre>
  987. *
  988. */
  989. public static class CloseShortcut extends ShortcutListener {
  990. protected Window window;
  991. /**
  992. * Creates a keyboard shortcut for closing the given window using the
  993. * shorthand notation defined in {@link ShortcutAction}.
  994. *
  995. * @param window
  996. * to be closed when the shortcut is invoked
  997. * @param shorthandCaption
  998. * the caption with shortcut keycode and modifiers indicated
  999. */
  1000. public CloseShortcut(Window window, String shorthandCaption) {
  1001. super(shorthandCaption);
  1002. this.window = window;
  1003. }
  1004. /**
  1005. * Creates a keyboard shortcut for closing the given window using the
  1006. * given {@link KeyCode} and {@link ModifierKey}s.
  1007. *
  1008. * @param window
  1009. * to be closed when the shortcut is invoked
  1010. * @param keyCode
  1011. * KeyCode to react to
  1012. * @param modifiers
  1013. * optional modifiers for shortcut
  1014. */
  1015. public CloseShortcut(Window window, int keyCode, int... modifiers) {
  1016. super(null, keyCode, modifiers);
  1017. this.window = window;
  1018. }
  1019. /**
  1020. * Creates a keyboard shortcut for closing the given window using the
  1021. * given {@link KeyCode}.
  1022. *
  1023. * @param window
  1024. * to be closed when the shortcut is invoked
  1025. * @param keyCode
  1026. * KeyCode to react to
  1027. */
  1028. public CloseShortcut(Window window, int keyCode) {
  1029. this(window, keyCode, null);
  1030. }
  1031. @Override
  1032. public void handleAction(Object sender, Object target) {
  1033. if (window.isClosable()) {
  1034. window.close();
  1035. }
  1036. }
  1037. public boolean equals(int keyCode, int... modifiers) {
  1038. if (keyCode != getKeyCode()) {
  1039. return false;
  1040. }
  1041. if (getModifiers() != null) {
  1042. int[] mods = null;
  1043. if (modifiers != null) {
  1044. // Modifiers provided by the parent ShortcutAction class
  1045. // are guaranteed to be sorted. We still need to sort
  1046. // the modifiers passed in as argument.
  1047. mods = Arrays.copyOf(modifiers, modifiers.length);
  1048. Arrays.sort(mods);
  1049. }
  1050. return Arrays.equals(mods, getModifiers());
  1051. }
  1052. return true;
  1053. }
  1054. }
  1055. /*
  1056. * (non-Javadoc)
  1057. *
  1058. * @see
  1059. * com.vaadin.event.FieldEvents.FocusNotifier#addFocusListener(com.vaadin
  1060. * .event.FieldEvents.FocusListener)
  1061. */
  1062. @Override
  1063. public Registration addFocusListener(FocusListener listener) {
  1064. return addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
  1065. FocusListener.focusMethod);
  1066. }
  1067. @Override
  1068. @Deprecated
  1069. public void removeFocusListener(FocusListener listener) {
  1070. removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
  1071. }
  1072. /*
  1073. * (non-Javadoc)
  1074. *
  1075. * @see
  1076. * com.vaadin.event.FieldEvents.BlurNotifier#addBlurListener(com.vaadin.
  1077. * event.FieldEvents.BlurListener)
  1078. */
  1079. @Override
  1080. public Registration addBlurListener(BlurListener listener) {
  1081. return addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
  1082. BlurListener.blurMethod);
  1083. }
  1084. @Override
  1085. @Deprecated
  1086. public void removeBlurListener(BlurListener listener) {
  1087. removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
  1088. }
  1089. /**
  1090. * {@inheritDoc}
  1091. *
  1092. * Cause the window to be brought on top of other windows and gain keyboard
  1093. * focus.
  1094. */
  1095. @Override
  1096. public void focus() {
  1097. /*
  1098. * When focusing a window it basically means it should be brought to the
  1099. * front. Instead of just moving the keyboard focus we focus the window
  1100. * and bring it top-most.
  1101. */
  1102. super.focus();
  1103. bringToFront();
  1104. }
  1105. @Override
  1106. protected WindowState getState() {
  1107. return (WindowState) super.getState();
  1108. }
  1109. @Override
  1110. protected WindowState getState(boolean markAsDirty) {
  1111. return (WindowState) super.getState(markAsDirty);
  1112. }
  1113. /**
  1114. * Allows to specify which components contain the description for the
  1115. * window. Text contained in these components will be read by assistive
  1116. * devices when it is opened.
  1117. *
  1118. * @param components
  1119. * the components to use as description
  1120. */
  1121. public void setAssistiveDescription(Component... components) {
  1122. if (components == null) {
  1123. throw new IllegalArgumentException(
  1124. "Parameter connectors must be non-null");
  1125. } else {
  1126. getState().contentDescription = components;
  1127. }
  1128. }
  1129. /**
  1130. * Gets the components that are used as assistive description. Text
  1131. * contained in these components will be read by assistive devices when the
  1132. * window is opened.
  1133. *
  1134. * @return array of previously set components
  1135. */
  1136. public Component[] getAssistiveDescription() {
  1137. Connector[] contentDescription = getState(false).contentDescription;
  1138. if (contentDescription == null) {
  1139. return null;
  1140. }
  1141. Component[] target = new Component[contentDescription.length];
  1142. System.arraycopy(contentDescription, 0, target, 0,
  1143. contentDescription.length);
  1144. return target;
  1145. }
  1146. /**
  1147. * Sets the accessibility prefix for the window caption.
  1148. *
  1149. * This prefix is read to assistive device users before the window caption,
  1150. * but not visible on the page.
  1151. *
  1152. * @param prefix
  1153. * String that is placed before the window caption
  1154. */
  1155. public void setAssistivePrefix(String prefix) {
  1156. getState().assistivePrefix = prefix;
  1157. }
  1158. /**
  1159. * Gets the accessibility prefix for the window caption.
  1160. *
  1161. * This prefix is read to assistive device users before the window caption,
  1162. * but not visible on the page.
  1163. *
  1164. * @return The accessibility prefix
  1165. */
  1166. public String getAssistivePrefix() {
  1167. return getState(false).assistivePrefix;
  1168. }
  1169. /**
  1170. * Sets the accessibility postfix for the window caption.
  1171. *
  1172. * This postfix is read to assistive device users after the window caption,
  1173. * but not visible on the page.
  1174. *
  1175. * @param prefix
  1176. * String that is placed after the window caption
  1177. */
  1178. public void setAssistivePostfix(String assistivePostfix) {
  1179. getState().assistivePostfix = assistivePostfix;
  1180. }
  1181. /**
  1182. * Gets the accessibility postfix for the window caption.
  1183. *
  1184. * This postfix is read to assistive device users after the window caption,
  1185. * but not visible on the page.
  1186. *
  1187. * @return The accessibility postfix
  1188. */
  1189. public String getAssistivePostfix() {
  1190. return getState(false).assistivePostfix;
  1191. }
  1192. /**
  1193. * Sets the WAI-ARIA role the window.
  1194. *
  1195. * This role defines how an assistive device handles a window. Available
  1196. * roles are alertdialog and dialog (@see
  1197. * <a href="http://www.w3.org/TR/2011/CR-wai-aria-20110118/roles">Roles
  1198. * Model</a>).
  1199. *
  1200. * The default role is dialog.
  1201. *
  1202. * @param role
  1203. * WAI-ARIA role to set for the window
  1204. */
  1205. public void setAssistiveRole(WindowRole role) {
  1206. getState().role = role;
  1207. }
  1208. /**
  1209. * Gets the WAI-ARIA role the window.
  1210. *
  1211. * This role defines how an assistive device handles a window. Available
  1212. * roles are alertdialog and dialog (@see
  1213. * <a href="http://www.w3.org/TR/2011/CR-wai-aria-20110118/roles">Roles
  1214. * Model</a>).
  1215. *
  1216. * @return WAI-ARIA role set for the window
  1217. */
  1218. public WindowRole getAssistiveRole() {
  1219. return getState(false).role;
  1220. }
  1221. /**
  1222. * Set if it should be prevented to set the focus to a component outside a
  1223. * non-modal window with the tab key.
  1224. * <p>
  1225. * This is meant to help users of assistive devices to not leaving the
  1226. * window unintentionally.
  1227. * <p>
  1228. * For modal windows, this function is activated automatically, while
  1229. * preserving the stored value of tabStop.
  1230. *
  1231. * @param tabStop
  1232. * true to keep the focus inside the window when reaching the top
  1233. * or bottom, false (default) to allow leaving the window
  1234. */
  1235. public void setTabStopEnabled(boolean tabStop) {
  1236. getState().assistiveTabStop = tabStop;
  1237. }
  1238. /**
  1239. * Get if it is prevented to leave a window with the tab key.
  1240. *
  1241. * @return true when the focus is limited to inside the window, false when
  1242. * focus can leave the window
  1243. */
  1244. public boolean isTabStopEnabled() {
  1245. return getState(false).assistiveTabStop;
  1246. }
  1247. /**
  1248. * Sets the message that is provided to users of assistive devices when the
  1249. * user reaches the top of the window when leaving a window with the tab key
  1250. * is prevented.
  1251. * <p>
  1252. * This message is not visible on the screen.
  1253. *
  1254. * @param topMessage
  1255. * String provided when the user navigates with Shift-Tab keys to
  1256. * the top of the window
  1257. */
  1258. public void setTabStopTopAssistiveText(String topMessage) {
  1259. getState().assistiveTabStopTopText = topMessage;
  1260. }
  1261. /**
  1262. * Sets the message that is provided to users of assistive devices when the
  1263. * user reaches the bottom of the window when leaving a window with the tab
  1264. * key is prevented.
  1265. * <p>
  1266. * This message is not visible on the screen.
  1267. *
  1268. * @param bottomMessage
  1269. * String provided when the user navigates with the Tab key to
  1270. * the bottom of the window
  1271. */
  1272. public void setTabStopBottomAssistiveText(String bottomMessage) {
  1273. getState().assistiveTabStopBottomText = bottomMessage;
  1274. }
  1275. /**
  1276. * Gets the message that is provided to users of assistive devices when the
  1277. * user reaches the top of the window when leaving a window with the tab key
  1278. * is prevented.
  1279. *
  1280. * @return the top message
  1281. */
  1282. public String getTabStopTopAssistiveText() {
  1283. return getState(false).assistiveTabStopTopText;
  1284. }
  1285. /**
  1286. * Gets the message that is provided to users of assistive devices when the
  1287. * user reaches the bottom of the window when leaving a window with the tab
  1288. * key is prevented.
  1289. *
  1290. * @return the bottom message
  1291. */
  1292. public String getTabStopBottomAssistiveText() {
  1293. return getState(false).assistiveTabStopBottomText;
  1294. }
  1295. @Override
  1296. public void readDesign(Element design, DesignContext context) {
  1297. super.readDesign(design, context);
  1298. if (design.hasAttr("center")) {
  1299. center();
  1300. }
  1301. if (design.hasAttr("position")) {
  1302. String[] position = design.attr("position").split(",");
  1303. setPositionX(Integer.parseInt(position[0]));
  1304. setPositionY(Integer.parseInt(position[1]));
  1305. }
  1306. // Parse shortcuts if defined, otherwise rely on default behavior
  1307. if (design.hasAttr("close-shortcut")) {
  1308. // Parse shortcuts
  1309. String[] shortcutStrings = DesignAttributeHandler
  1310. .readAttribute("close-shortcut", design.attributes(),
  1311. String.class)
  1312. .split("\\s+");
  1313. removeAllCloseShortcuts();
  1314. for (String part : shortcutStrings) {
  1315. if (!part.isEmpty()) {
  1316. ShortcutAction shortcut = DesignAttributeHandler
  1317. .getFormatter()
  1318. .parse(part.trim(), ShortcutAction.class);
  1319. addCloseShortcut(shortcut.getKeyCode(),
  1320. shortcut.getModifiers());
  1321. }
  1322. }
  1323. }
  1324. }
  1325. /**
  1326. * Reads the content and possible assistive descriptions from the list of
  1327. * child elements of a design. If an element has an
  1328. * {@code :assistive-description} attribute, adds the parsed component to
  1329. * the list of components used as the assistive description of this Window.
  1330. * Otherwise, sets the component as the content of this Window. If there are
  1331. * multiple non-description elements, throws a DesignException.
  1332. *
  1333. * @param children
  1334. * child elements in a design
  1335. * @param context
  1336. * the DesignContext instance used to parse the design
  1337. *
  1338. * @throws DesignException
  1339. * if there are multiple non-description child elements
  1340. * @throws DesignException
  1341. * if a child element could not be parsed as a Component
  1342. *
  1343. * @see #setContent(Component)
  1344. * @see #setAssistiveDescription(Component...)
  1345. */
  1346. @Override
  1347. protected void readDesignChildren(Elements children,
  1348. DesignContext context) {
  1349. List<Component> descriptions = new ArrayList<>();
  1350. Elements content = new Elements();
  1351. for (Element child : children) {
  1352. if (child.hasAttr(":assistive-description")) {
  1353. descriptions.add(context.readDesign(child));
  1354. } else {
  1355. content.add(child);
  1356. }
  1357. }
  1358. super.readDesignChildren(content, context);
  1359. setAssistiveDescription(
  1360. descriptions.toArray(new Component[descriptions.size()]));
  1361. }
  1362. @Override
  1363. public void writeDesign(Element design, DesignContext context) {
  1364. super.writeDesign(design, context);
  1365. Window def = context.getDefaultInstance(this);
  1366. if (getState().centered) {
  1367. design.attr("center", true);
  1368. }
  1369. DesignAttributeHandler.writeAttribute("position", design.attributes(),
  1370. getPosition(), def.getPosition(), String.class, context);
  1371. // Process keyboard shortcuts
  1372. if (closeShortcuts.size() == 1 && hasCloseShortcut(KeyCode.ESCAPE)) {
  1373. // By default, we won't write anything if we're relying on default
  1374. // shortcut behavior
  1375. } else {
  1376. // Dump all close shortcuts to a string...
  1377. String attrString = "";
  1378. // TODO: add canonical support for array data in XML attributes
  1379. for (CloseShortcut shortcut : closeShortcuts) {
  1380. String shortcutString = DesignAttributeHandler.getFormatter()
  1381. .format(shortcut, CloseShortcut.class);
  1382. attrString += shortcutString + " ";
  1383. }
  1384. // Write everything except the last "," to the design
  1385. DesignAttributeHandler.writeAttribute("close-shortcut",
  1386. design.attributes(), attrString.trim(), null, String.class,
  1387. context);
  1388. }
  1389. for (Component c : getAssistiveDescription()) {
  1390. Element child = context.createElement(c)
  1391. .attr(":assistive-description", true);
  1392. design.appendChild(child);
  1393. }
  1394. }
  1395. private String getPosition() {
  1396. return getPositionX() + "," + getPositionY();
  1397. }
  1398. @Override
  1399. protected Collection<String> getCustomAttributes() {
  1400. Collection<String> result = super.getCustomAttributes();
  1401. result.add("center");
  1402. result.add("position");
  1403. result.add("position-y");
  1404. result.add("position-x");
  1405. result.add("close-shortcut");
  1406. return result;
  1407. }
  1408. }