123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548 |
- /*
- * Copyright 2000-2016 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
- package com.vaadin.ui;
-
- import java.io.Serializable;
- import java.lang.reflect.Method;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.List;
- import java.util.Map;
-
- import org.jsoup.nodes.Element;
- import org.jsoup.select.Elements;
-
- import com.vaadin.event.ConnectorEventListener;
- import com.vaadin.event.FieldEvents.BlurEvent;
- import com.vaadin.event.FieldEvents.BlurListener;
- import com.vaadin.event.FieldEvents.BlurNotifier;
- import com.vaadin.event.FieldEvents.FocusEvent;
- import com.vaadin.event.FieldEvents.FocusListener;
- import com.vaadin.event.FieldEvents.FocusNotifier;
- import com.vaadin.event.MouseEvents.ClickEvent;
- import com.vaadin.event.ShortcutAction;
- import com.vaadin.event.ShortcutAction.KeyCode;
- import com.vaadin.event.ShortcutAction.ModifierKey;
- import com.vaadin.event.ShortcutListener;
- import com.vaadin.server.PaintException;
- import com.vaadin.server.PaintTarget;
- import com.vaadin.shared.Connector;
- import com.vaadin.shared.EventId;
- import com.vaadin.shared.MouseEventDetails;
- import com.vaadin.shared.Registration;
- import com.vaadin.shared.ui.window.WindowMode;
- import com.vaadin.shared.ui.window.WindowRole;
- import com.vaadin.shared.ui.window.WindowServerRpc;
- import com.vaadin.shared.ui.window.WindowState;
- import com.vaadin.ui.declarative.DesignAttributeHandler;
- import com.vaadin.ui.declarative.DesignContext;
- import com.vaadin.ui.declarative.DesignException;
- import com.vaadin.util.ReflectTools;
-
- /**
- * A component that represents a floating popup window that can be added to a
- * {@link UI}. A window is added to a {@code UI} using
- * {@link UI#addWindow(Window)}.
- * <p>
- * The contents of a window is set using {@link #setContent(Component)} or by
- * using the {@link #Window(String, Component)} constructor.
- * </p>
- * <p>
- * A window can be positioned on the screen using absolute coordinates (pixels)
- * or set to be centered using {@link #center()}
- * </p>
- * <p>
- * The caption is displayed in the window header.
- * </p>
- * <p>
- * In Vaadin versions prior to 7.0.0, Window was also used as application level
- * windows. This function is now covered by the {@link UI} class.
- * </p>
- *
- * @author Vaadin Ltd.
- * @since 3.0
- */
- @SuppressWarnings({ "serial", "deprecation" })
- public class Window extends Panel
- implements FocusNotifier, BlurNotifier, LegacyComponent {
-
- private WindowServerRpc rpc = new WindowServerRpc() {
-
- @Override
- public void click(MouseEventDetails mouseDetails) {
- fireEvent(new ClickEvent(Window.this, mouseDetails));
- }
-
- @Override
- public void windowModeChanged(WindowMode newState) {
- setWindowMode(newState);
- }
-
- @Override
- public void windowMoved(int x, int y) {
- if (x != getState(false).positionX) {
- setPositionX(x);
- }
- if (y != getState(false).positionY) {
- setPositionY(y);
- }
- }
- };
-
- /**
- * Holds registered CloseShortcut instances for query and later removal
- */
- private List<CloseShortcut> closeShortcuts = new ArrayList<>(4);
-
- /**
- * Used to keep the window order position. Order position for unattached
- * window is {@code -1}.
- * <p>
- * Window with greatest order position value is on the top and window with 0
- * position value is on the bottom.
- */
- private int orderPosition = -1;
-
- /**
- * Creates a new, empty window
- */
- public Window() {
- this("", null);
- }
-
- /**
- * Creates a new, empty window with a given title.
- *
- * @param caption
- * the title of the window.
- */
- public Window(String caption) {
- this(caption, null);
- }
-
- /**
- * Creates a new, empty window with the given content and title.
- *
- * @param caption
- * the title of the window.
- * @param content
- * the contents of the window
- */
- public Window(String caption, Component content) {
- super(caption, content);
- registerRpc(rpc);
- setSizeUndefined();
- setCloseShortcut(KeyCode.ESCAPE);
- }
-
- /* ********************************************************************* */
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.ui.Panel#paintContent(com.vaadin.server.PaintTarget)
- */
-
- @Override
- public synchronized void paintContent(PaintTarget target)
- throws PaintException {
- if (bringToFront != null) {
- target.addAttribute("bringToFront", bringToFront.intValue());
- bringToFront = null;
- }
-
- // Contents of the window panel is painted
- super.paintContent(target);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.ui.AbstractComponent#setParent(com.vaadin.server.
- * ClientConnector )
- */
- @Override
- public void setParent(HasComponents parent) {
- if (parent == null || parent instanceof UI) {
- super.setParent(parent);
- } else {
- throw new IllegalArgumentException(
- "A Window can only be added to a UI using UI.addWindow(Window window)");
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.ui.Panel#changeVariables(java.lang.Object, java.util.Map)
- */
-
- @Override
- public void changeVariables(Object source, Map<String, Object> variables) {
-
- // TODO Are these for top level windows or sub windows?
- boolean sizeHasChanged = false;
- // size is handled in super class, but resize events only in windows ->
- // so detect if size change occurs before super.changeVariables()
- if (variables.containsKey("height") && (getHeightUnits() != Unit.PIXELS
- || (Integer) variables.get("height") != getHeight())) {
- sizeHasChanged = true;
- }
- if (variables.containsKey("width") && (getWidthUnits() != Unit.PIXELS
- || (Integer) variables.get("width") != getWidth())) {
- sizeHasChanged = true;
- }
-
- super.changeVariables(source, variables);
-
- // Positioning
- final Integer positionx = (Integer) variables.get("positionx");
- if (positionx != null) {
- final int x = positionx.intValue();
- // This is information from the client so it is already using the
- // position. No need to repaint.
- setPositionX(x < 0 ? -1 : x);
- }
- final Integer positiony = (Integer) variables.get("positiony");
- if (positiony != null) {
- final int y = positiony.intValue();
- // This is information from the client so it is already using the
- // position. No need to repaint.
- setPositionY(y < 0 ? -1 : y);
- }
-
- if (isClosable()) {
- // Closing
- final Boolean close = (Boolean) variables.get("close");
- if (close != null && close.booleanValue()) {
- close();
- }
- }
-
- // fire event if size has really changed
- if (sizeHasChanged) {
- fireResize();
- }
-
- if (variables.containsKey(FocusEvent.EVENT_ID)) {
- fireEvent(new FocusEvent(this));
- } else if (variables.containsKey(BlurEvent.EVENT_ID)) {
- fireEvent(new BlurEvent(this));
- }
-
- }
-
- /**
- * Method that handles window closing (from UI).
- *
- * <p>
- * By default, windows are removed from their respective UIs and thus
- * visually closed on browser-side.
- * </p>
- *
- * <p>
- * To react to a window being closed (after it is closed), register a
- * {@link CloseListener}.
- * </p>
- */
- public void close() {
- UI uI = getUI();
-
- // Don't do anything if not attached to a UI
- if (uI != null) {
- // window is removed from the UI
- uI.removeWindow(this);
- }
- }
-
- /**
- * Gets the distance of Window left border in pixels from left border of the
- * containing (main window) when the window is in {@link WindowMode#NORMAL}.
- *
- * @return the Distance of Window left border in pixels from left border of
- * the containing (main window).or -1 if unspecified
- * @since 4.0.0
- */
- public int getPositionX() {
- return getState(false).positionX;
- }
-
- /**
- * Sets the position of the window on the screen using
- * {@link #setPositionX(int)} and {@link #setPositionY(int)}
- *
- * @since 7.5
- * @param x
- * The new x coordinate for the window
- * @param y
- * The new y coordinate for the window
- */
- public void setPosition(int x, int y) {
- setPositionX(x);
- setPositionY(y);
- }
-
- /**
- * Sets the distance of Window left border in pixels from left border of the
- * containing (main window). Has effect only if in {@link WindowMode#NORMAL}
- * mode.
- *
- * @param positionX
- * the Distance of Window left border in pixels from left border
- * of the containing (main window). or -1 if unspecified.
- * @since 4.0.0
- */
- public void setPositionX(int positionX) {
- getState().positionX = positionX;
- getState().centered = false;
- }
-
- /**
- * Gets the distance of Window top border in pixels from top border of the
- * containing (main window) when the window is in {@link WindowMode#NORMAL}
- * state, or when next set to that state.
- *
- * @return Distance of Window top border in pixels from top border of the
- * containing (main window). or -1 if unspecified
- *
- * @since 4.0.0
- */
- public int getPositionY() {
- return getState(false).positionY;
- }
-
- /**
- * Returns the position of this window in the order of all open windows for
- * this UI.
- * <p>
- * Window with position 0 is on the bottom, and window with greatest
- * position is at the top. If window has no position (it's not yet attached
- * or hidden) then position is {@code -1}.
- *
- * @see UI#addWindowOrderUpdateListener(com.vaadin.ui.UI.WindowOrderUpdateListener)
- *
- * @since 8.0
- *
- * @return window order position.
- */
- public int getOrderPosition() {
- return orderPosition;
- }
-
- /**
- * Sets the distance of Window top border in pixels from top border of the
- * containing (main window). Has effect only if in {@link WindowMode#NORMAL}
- * mode.
- *
- * @param positionY
- * the Distance of Window top border in pixels from top border of
- * the containing (main window). or -1 if unspecified
- *
- * @since 4.0.0
- */
- public void setPositionY(int positionY) {
- getState().positionY = positionY;
- getState().centered = false;
- }
-
- private static final Method WINDOW_CLOSE_METHOD;
- static {
- try {
- WINDOW_CLOSE_METHOD = CloseListener.class
- .getDeclaredMethod("windowClose", CloseEvent.class);
- } catch (final java.lang.NoSuchMethodException e) {
- // This should never happen
- throw new java.lang.RuntimeException(
- "Internal error, window close method not found");
- }
- }
-
- public static class CloseEvent extends Component.Event {
-
- /**
- *
- * @param source
- */
- public CloseEvent(Component source) {
- super(source);
- }
-
- /**
- * Gets the Window.
- *
- * @return the window.
- */
- public Window getWindow() {
- return (Window) getSource();
- }
- }
-
- /**
- * Event which is fired when the window order position is changed.
- *
- * @see UI.WindowOrderUpdateEvent
- *
- * @author Vaadin Ltd
- *
- */
- public static class WindowOrderChangeEvent extends Component.Event {
-
- private final int order;
-
- public WindowOrderChangeEvent(Component source, int order) {
- super(source);
- this.order = order;
- }
-
- /**
- * Gets the Window.
- *
- * @return the window
- */
- public Window getWindow() {
- return (Window) getSource();
- }
-
- /**
- * Gets the new window order position.
- *
- * @return the new order position
- */
- public int getOrder() {
- return order;
- }
- }
-
- /**
- * An interface used for listening to Window order change events.
- *
- * @see UI.WindowOrderUpdateListener
- */
- @FunctionalInterface
- public interface WindowOrderChangeListener extends ConnectorEventListener {
-
- public static final Method windowOrderChangeMethod = ReflectTools
- .findMethod(WindowOrderChangeListener.class,
- "windowOrderChanged", WindowOrderChangeEvent.class);
-
- /**
- * Called when the window order position is changed. Use
- * {@link WindowOrderChangeEvent#getWindow()} to get a reference to the
- * {@link Window} whose order position is changed. Use
- * {@link WindowOrderChangeEvent#getOrder()} to get a new order
- * position.
- *
- * @param event
- */
- public void windowOrderChanged(WindowOrderChangeEvent event);
- }
-
- /**
- * Adds a WindowOrderChangeListener to the window.
- * <p>
- * The WindowOrderChangeEvent is fired when the order position is changed.
- * It can happen when some window (this or other) is brought to front or
- * detached.
- * <p>
- * The other way to listen positions of all windows in UI is
- * {@link UI#addWindowOrderUpdateListener(com.vaadin.ui.UI.WindowOrderUpdateListener)}
- *
- * @see UI#addWindowOrderUpdateListener(com.vaadin.ui.UI.WindowOrderUpdateListener)
- *
- * @param listener
- * the WindowModeChangeListener to add.
- * @since 8.0
- */
- public Registration addWindowOrderChangeListener(
- WindowOrderChangeListener listener) {
- addListener(EventId.WINDOW_ORDER, WindowOrderChangeEvent.class,
- listener, WindowOrderChangeListener.windowOrderChangeMethod);
- return () -> removeListener(EventId.WINDOW_ORDER,
- WindowOrderChangeEvent.class, listener);
- }
-
- protected void fireWindowOrderChange(Integer order) {
- if (order == null || orderPosition != order) {
- orderPosition = (order == null) ? -1 : order;
- fireEvent(new Window.WindowOrderChangeEvent(this,
- getOrderPosition()));
- }
- }
-
- /**
- * An interface used for listening to Window close events. Add the
- * CloseListener to a window and
- * {@link CloseListener#windowClose(CloseEvent)} will be called whenever the
- * user closes the window.
- *
- * <p>
- * Since Vaadin 6.5, removing a window using {@link #removeWindow(Window)}
- * fires the CloseListener.
- * </p>
- */
- @FunctionalInterface
- public interface CloseListener extends Serializable {
- /**
- * Called when the user closes a window. Use
- * {@link CloseEvent#getWindow()} to get a reference to the
- * {@link Window} that was closed.
- *
- * @param e
- * Event containing
- */
- public void windowClose(CloseEvent e);
- }
-
- /**
- * Adds a CloseListener to the window.
- *
- * For a window the CloseListener is fired when the user closes it (clicks
- * on the close button).
- *
- * For a browser level window the CloseListener is fired when the browser
- * level window is closed. Note that closing a browser level window does not
- * mean it will be destroyed. Also note that Opera does not send events like
- * all other browsers and therefore the close listener might not be called
- * if Opera is used.
- *
- * <p>
- * Since Vaadin 6.5, removing windows using {@link #removeWindow(Window)}
- * does fire the CloseListener.
- * </p>
- *
- * @param listener
- * the CloseListener to add, not null
- * @since 8.0
- */
- public Registration addCloseListener(CloseListener listener) {
- return addListener(CloseEvent.class, listener, WINDOW_CLOSE_METHOD);
- }
-
- /**
- * Removes the CloseListener from the window.
- *
- * <p>
- * For more information on CloseListeners see {@link CloseListener}.
- * </p>
- *
- * @param listener
- * the CloseListener to remove.
- */
- @Deprecated
- public void removeCloseListener(CloseListener listener) {
- removeListener(CloseEvent.class, listener, WINDOW_CLOSE_METHOD);
- }
-
- protected void fireClose() {
- fireEvent(new Window.CloseEvent(this));
- }
-
- /**
- * Event which is fired when the mode of the Window changes.
- *
- * @author Vaadin Ltd
- * @since 7.1
- *
- */
- public static class WindowModeChangeEvent extends Component.Event {
-
- private final WindowMode windowMode;
-
- /**
- *
- * @param source
- */
- public WindowModeChangeEvent(Component source, WindowMode windowMode) {
- super(source);
- this.windowMode = windowMode;
- }
-
- /**
- * Gets the Window.
- *
- * @return the window
- */
- public Window getWindow() {
- return (Window) getSource();
- }
-
- /**
- * Gets the new window mode.
- *
- * @return the new mode
- */
- public WindowMode getWindowMode() {
- return windowMode;
- }
- }
-
- /**
- * An interface used for listening to Window maximize / restore events. Add
- * the WindowModeChangeListener to a window and
- * {@link WindowModeChangeListener#windowModeChanged(WindowModeChangeEvent)}
- * will be called whenever the window is maximized (
- * {@link WindowMode#MAXIMIZED}) or restored ({@link WindowMode#NORMAL} ).
- */
- @FunctionalInterface
- public interface WindowModeChangeListener extends Serializable {
-
- public static final Method windowModeChangeMethod = ReflectTools
- .findMethod(WindowModeChangeListener.class, "windowModeChanged",
- WindowModeChangeEvent.class);
-
- /**
- * Called when the user maximizes / restores a window. Use
- * {@link WindowModeChangeEvent#getWindow()} to get a reference to the
- * {@link Window} that was maximized / restored. Use
- * {@link WindowModeChangeEvent#getWindowMode()} to get a reference to
- * the new state.
- *
- * @param event
- */
- public void windowModeChanged(WindowModeChangeEvent event);
- }
-
- /**
- * Adds a WindowModeChangeListener to the window.
- *
- * The WindowModeChangeEvent is fired when the user changed the display
- * state by clicking the maximize/restore button or by double clicking on
- * the window header. The event is also fired if the state is changed using
- * {@link #setWindowMode(WindowMode)}.
- *
- * @param listener
- * the WindowModeChangeListener to add.
- * @since 8.0
- */
- public Registration addWindowModeChangeListener(
- WindowModeChangeListener listener) {
- return addListener(WindowModeChangeEvent.class, listener,
- WindowModeChangeListener.windowModeChangeMethod);
- }
-
- /**
- * Removes the WindowModeChangeListener from the window.
- *
- * @param listener
- * the WindowModeChangeListener to remove.
- */
- @Deprecated
- public void removeWindowModeChangeListener(
- WindowModeChangeListener listener) {
- removeListener(WindowModeChangeEvent.class, listener,
- WindowModeChangeListener.windowModeChangeMethod);
- }
-
- protected void fireWindowWindowModeChange() {
- fireEvent(
- new Window.WindowModeChangeEvent(this, getState().windowMode));
- }
-
- /**
- * Method for the resize event.
- */
- private static final Method WINDOW_RESIZE_METHOD;
- static {
- try {
- WINDOW_RESIZE_METHOD = ResizeListener.class
- .getDeclaredMethod("windowResized", ResizeEvent.class);
- } catch (final java.lang.NoSuchMethodException e) {
- // This should never happen
- throw new java.lang.RuntimeException(
- "Internal error, window resized method not found");
- }
- }
-
- /**
- * Resize events are fired whenever the client-side fires a resize-event
- * (e.g. the browser window is resized). The frequency may vary across
- * browsers.
- */
- public static class ResizeEvent extends Component.Event {
-
- /**
- *
- * @param source
- */
- public ResizeEvent(Component source) {
- super(source);
- }
-
- /**
- * Get the window form which this event originated
- *
- * @return the window
- */
- public Window getWindow() {
- return (Window) getSource();
- }
- }
-
- /**
- * Listener for window resize events.
- *
- * @see com.vaadin.ui.Window.ResizeEvent
- */
- @FunctionalInterface
- public interface ResizeListener extends Serializable {
- public void windowResized(ResizeEvent e);
- }
-
- /**
- * Add a resize listener.
- *
- * @see Registration
- *
- * @param listener
- * the listener to add, not null
- * @return a registration object for removing the listener
- * @since 8.0
- */
- public Registration addResizeListener(ResizeListener listener) {
- return addListener(ResizeEvent.class, listener, WINDOW_RESIZE_METHOD);
- }
-
- /**
- * Remove a resize listener.
- *
- * @param listener
- */
- @Deprecated
- public void removeResizeListener(ResizeListener listener) {
- removeListener(ResizeEvent.class, listener);
- }
-
- /**
- * Fire the resize event.
- */
- protected void fireResize() {
- fireEvent(new ResizeEvent(this));
- }
-
- /**
- * Used to keep the right order of windows if multiple windows are brought
- * to front in a single changeset. If this is not used, the order is quite
- * random (depends on the order getting to dirty list. e.g. which window got
- * variable changes).
- */
- private Integer bringToFront = null;
-
- /**
- * If there are currently several windows visible, calling this method makes
- * this window topmost.
- * <p>
- * This method can only be called if this window connected a UI. Else an
- * illegal state exception is thrown. Also if there are modal windows and
- * this window is not modal, and illegal state exception is thrown.
- * <p>
- */
- public void bringToFront() {
- UI uI = getUI();
- if (uI == null) {
- throw new IllegalStateException(
- "Window must be attached to parent before calling bringToFront method.");
- }
- int maxBringToFront = -1;
- for (Window w : uI.getWindows()) {
- if (!isModal() && w.isModal()) {
- throw new IllegalStateException(
- "The UI contains modal windows, non-modal window cannot be brought to front.");
- }
- if (w.bringToFront != null) {
- maxBringToFront = Math.max(maxBringToFront,
- w.bringToFront.intValue());
- }
- }
- bringToFront = Integer.valueOf(maxBringToFront + 1);
- markAsDirty();
- }
-
- /**
- * Sets window modality. When a modal window is open, components outside
- * that window cannot be accessed.
- * <p>
- * Keyboard navigation is restricted by blocking the tab key at the top and
- * bottom of the window by activating the tab stop function internally.
- *
- * @param modal
- * true if modality is to be turned on
- */
- public void setModal(boolean modal) {
- getState().modal = modal;
- center();
- }
-
- /**
- * @return true if this window is modal.
- */
- public boolean isModal() {
- return getState(false).modal;
- }
-
- /**
- * Sets window resizable.
- *
- * @param resizable
- * true if resizability is to be turned on
- */
- public void setResizable(boolean resizable) {
- getState().resizable = resizable;
- }
-
- /**
- *
- * @return true if window is resizable by the end-user, otherwise false.
- */
- public boolean isResizable() {
- return getState(false).resizable;
- }
-
- /**
- *
- * @return true if a delay is used before recalculating sizes, false if
- * sizes are recalculated immediately.
- */
- public boolean isResizeLazy() {
- return getState(false).resizeLazy;
- }
-
- /**
- * Should resize operations be lazy, i.e. should there be a delay before
- * layout sizes are recalculated. Speeds up resize operations in slow UIs
- * with the penalty of slightly decreased usability.
- *
- * Note, some browser send false resize events for the browser window and
- * are therefore always lazy.
- *
- * @param resizeLazy
- * true to use a delay before recalculating sizes, false to
- * calculate immediately.
- */
- public void setResizeLazy(boolean resizeLazy) {
- getState().resizeLazy = resizeLazy;
- }
-
- /**
- * Sets this window to be centered relative to its parent window. Affects
- * windows only. If the window is resized as a result of the size of its
- * content changing, it will keep itself centered as long as its position is
- * not explicitly changed programmatically or by the user.
- * <p>
- * <b>NOTE:</b> This method has several issues as currently implemented.
- * Please refer to http://dev.vaadin.com/ticket/8971 for details.
- */
- public void center() {
- getState().centered = true;
- }
-
- /**
- * Returns the closable status of the window. If a window is closable, it
- * typically shows an X in the upper right corner. Clicking on the X sends a
- * close event to the server. Setting closable to false will remove the X
- * from the window and prevent the user from closing the window.
- *
- * @return true if the window can be closed by the user.
- */
- public boolean isClosable() {
- return getState(false).closable;
- }
-
- /**
- * Sets the closable status for the window. If a window is closable it
- * typically shows an X in the upper right corner. Clicking on the X sends a
- * close event to the server. Setting closable to false will remove the X
- * from the window and prevent the user from closing the window.
- *
- * @param closable
- * determines if the window can be closed by the user.
- */
- public void setClosable(boolean closable) {
- if (closable != isClosable()) {
- getState().closable = closable;
- }
- }
-
- /**
- * Indicates whether a window can be dragged or not. By default a window is
- * draggable.
- *
- * @return {@code true} if window is draggable; {@code false} if not
- */
- public boolean isDraggable() {
- return getState(false).draggable;
- }
-
- /**
- * Enables or disables that a window can be dragged (moved) by the user. By
- * default a window is draggable.
- * <p/>
- *
- * @param draggable
- * true if the window can be dragged by the user
- */
- public void setDraggable(boolean draggable) {
- getState().draggable = draggable;
- }
-
- /**
- * Gets the current mode of the window.
- *
- * @see WindowMode
- * @return the mode of the window.
- */
- public WindowMode getWindowMode() {
- return getState(false).windowMode;
- }
-
- /**
- * Sets the mode for the window
- *
- * @see WindowMode
- * @param windowMode
- * The new mode
- */
- public void setWindowMode(WindowMode windowMode) {
- if (windowMode != getWindowMode()) {
- getState().windowMode = windowMode;
- fireWindowWindowModeChange();
- }
- }
-
- /**
- * This is the old way of adding a keyboard shortcut to close a
- * {@link Window} - to preserve compatibility with existing code under the
- * new functionality, this method now first removes all registered close
- * shortcuts, then adds the default ESCAPE shortcut key, and then attempts
- * to add the shortcut provided as parameters to this method. This method,
- * and its companion {@link #removeCloseShortcut()}, are now considered
- * deprecated, as their main function is to preserve exact backwards
- * compatibility with old code. For all new code, use the new keyboard
- * shortcuts API: {@link #addCloseShortcut(int,int...)},
- * {@link #removeCloseShortcut(int,int...)},
- * {@link #removeAllCloseShortcuts()}, {@link #hasCloseShortcut(int,int...)}
- * and {@link #getCloseShortcuts()}.
- * <p>
- * Original description: Makes it possible to close the window by pressing
- * the given {@link KeyCode} and (optional) {@link ModifierKey}s.<br/>
- * Note that this shortcut only reacts while the window has focus, closing
- * itself - if you want to close a window from a UI, use
- * {@link UI#addAction(com.vaadin.event.Action)} of the UI instead.
- *
- * @param keyCode
- * the keycode for invoking the shortcut
- * @param modifiers
- * the (optional) modifiers for invoking the shortcut. Can be set
- * to null to be explicit about not having modifiers.
- *
- * @deprecated Use {@link #addCloseShortcut(int, int...)} instead.
- */
- @Deprecated
- public void setCloseShortcut(int keyCode, int... modifiers) {
- removeCloseShortcut();
- addCloseShortcut(keyCode, modifiers);
- }
-
- /**
- * Removes all keyboard shortcuts previously set with
- * {@link #setCloseShortcut(int, int...)} and
- * {@link #addCloseShortcut(int, int...)}, then adds the default
- * {@link KeyCode#ESCAPE} shortcut.
- * <p>
- * This is the old way of removing the (single) keyboard close shortcut, and
- * is retained only for exact backwards compatibility. For all new code, use
- * the new keyboard shortcuts API: {@link #addCloseShortcut(int,int...)},
- * {@link #removeCloseShortcut(int,int...)},
- * {@link #removeAllCloseShortcuts()}, {@link #hasCloseShortcut(int,int...)}
- * and {@link #getCloseShortcuts()}.
- *
- * @deprecated Use {@link #removeCloseShortcut(int, int...)} instead.
- */
- @Deprecated
- public void removeCloseShortcut() {
- for (CloseShortcut sc : closeShortcuts) {
- removeAction(sc);
- }
- closeShortcuts.clear();
- addCloseShortcut(KeyCode.ESCAPE);
- }
-
- /**
- * Adds a close shortcut - pressing this key while holding down all (if any)
- * modifiers specified while this Window is in focus will close the Window.
- *
- * @since 7.6
- * @param keyCode
- * the keycode for invoking the shortcut
- * @param modifiers
- * the (optional) modifiers for invoking the shortcut. Can be set
- * to null to be explicit about not having modifiers.
- */
- public void addCloseShortcut(int keyCode, int... modifiers) {
-
- // Ignore attempts to re-add existing shortcuts
- if (hasCloseShortcut(keyCode, modifiers)) {
- return;
- }
-
- // Actually add the shortcut
- CloseShortcut shortcut = new CloseShortcut(this, keyCode, modifiers);
- addAction(shortcut);
- closeShortcuts.add(shortcut);
- }
-
- /**
- * Removes a close shortcut previously added with
- * {@link #addCloseShortcut(int, int...)}.
- *
- * @since 7.6
- * @param keyCode
- * the keycode for invoking the shortcut
- * @param modifiers
- * the (optional) modifiers for invoking the shortcut. Can be set
- * to null to be explicit about not having modifiers.
- */
- public void removeCloseShortcut(int keyCode, int... modifiers) {
- for (CloseShortcut shortcut : closeShortcuts) {
- if (shortcut.equals(keyCode, modifiers)) {
- removeAction(shortcut);
- closeShortcuts.remove(shortcut);
- return;
- }
- }
- }
-
- /**
- * Removes all close shortcuts. This includes the default ESCAPE shortcut.
- * It is up to the user to add back any and all keyboard close shortcuts
- * they may require. For more fine-grained control over shortcuts, use
- * {@link #removeCloseShortcut(int, int...)}.
- *
- * @since 7.6
- */
- public void removeAllCloseShortcuts() {
- for (CloseShortcut shortcut : closeShortcuts) {
- removeAction(shortcut);
- }
- closeShortcuts.clear();
- }
-
- /**
- * Checks if a close window shortcut key has already been registered.
- *
- * @since 7.6
- * @param keyCode
- * the keycode for invoking the shortcut
- * @param modifiers
- * the (optional) modifiers for invoking the shortcut. Can be set
- * to null to be explicit about not having modifiers.
- * @return true, if an exactly matching shortcut has been registered.
- */
- public boolean hasCloseShortcut(int keyCode, int... modifiers) {
- for (CloseShortcut shortcut : closeShortcuts) {
- if (shortcut.equals(keyCode, modifiers)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns an unmodifiable collection of {@link CloseShortcut} objects
- * currently registered with this {@link Window}. This method is provided
- * mainly so that users can implement their own serialization routines. To
- * check if a certain combination of keys has been registered as a close
- * shortcut, use the {@link #hasCloseShortcut(int, int...)} method instead.
- *
- * @since 7.6
- * @return an unmodifiable Collection of CloseShortcut objects.
- */
- public Collection<CloseShortcut> getCloseShortcuts() {
- return Collections.unmodifiableCollection(closeShortcuts);
- }
-
- /**
- * A {@link ShortcutListener} specifically made to define a keyboard
- * shortcut that closes the window.
- *
- * <pre>
- * <code>
- * // within the window using helper
- * window.setCloseShortcut(KeyCode.ESCAPE, null);
- *
- * // or globally
- * getUI().addAction(new Window.CloseShortcut(window, KeyCode.ESCAPE));
- * </code>
- * </pre>
- *
- */
- public static class CloseShortcut extends ShortcutListener {
- protected Window window;
-
- /**
- * Creates a keyboard shortcut for closing the given window using the
- * shorthand notation defined in {@link ShortcutAction}.
- *
- * @param window
- * to be closed when the shortcut is invoked
- * @param shorthandCaption
- * the caption with shortcut keycode and modifiers indicated
- */
- public CloseShortcut(Window window, String shorthandCaption) {
- super(shorthandCaption);
- this.window = window;
- }
-
- /**
- * Creates a keyboard shortcut for closing the given window using the
- * given {@link KeyCode} and {@link ModifierKey}s.
- *
- * @param window
- * to be closed when the shortcut is invoked
- * @param keyCode
- * KeyCode to react to
- * @param modifiers
- * optional modifiers for shortcut
- */
- public CloseShortcut(Window window, int keyCode, int... modifiers) {
- super(null, keyCode, modifiers);
- this.window = window;
- }
-
- /**
- * Creates a keyboard shortcut for closing the given window using the
- * given {@link KeyCode}.
- *
- * @param window
- * to be closed when the shortcut is invoked
- * @param keyCode
- * KeyCode to react to
- */
- public CloseShortcut(Window window, int keyCode) {
- this(window, keyCode, null);
- }
-
- @Override
- public void handleAction(Object sender, Object target) {
- if (window.isClosable()) {
- window.close();
- }
- }
-
- public boolean equals(int keyCode, int... modifiers) {
- if (keyCode != getKeyCode()) {
- return false;
- }
-
- if (getModifiers() != null) {
- int[] mods = null;
- if (modifiers != null) {
- // Modifiers provided by the parent ShortcutAction class
- // are guaranteed to be sorted. We still need to sort
- // the modifiers passed in as argument.
- mods = Arrays.copyOf(modifiers, modifiers.length);
- Arrays.sort(mods);
- }
- return Arrays.equals(mods, getModifiers());
- }
- return true;
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * com.vaadin.event.FieldEvents.FocusNotifier#addFocusListener(com.vaadin
- * .event.FieldEvents.FocusListener)
- */
- @Override
- public Registration addFocusListener(FocusListener listener) {
- return addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
- FocusListener.focusMethod);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * com.vaadin.event.FieldEvents.BlurNotifier#addBlurListener(com.vaadin.
- * event.FieldEvents.BlurListener)
- */
- @Override
- public Registration addBlurListener(BlurListener listener) {
- return addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
- BlurListener.blurMethod);
- }
-
- /**
- * {@inheritDoc}
- *
- * Cause the window to be brought on top of other windows and gain keyboard
- * focus.
- */
- @Override
- public void focus() {
- /*
- * When focusing a window it basically means it should be brought to the
- * front. Instead of just moving the keyboard focus we focus the window
- * and bring it top-most.
- */
- super.focus();
- bringToFront();
- }
-
- @Override
- protected WindowState getState() {
- return (WindowState) super.getState();
- }
-
- @Override
- protected WindowState getState(boolean markAsDirty) {
- return (WindowState) super.getState(markAsDirty);
- }
-
- /**
- * Allows to specify which components contain the description for the
- * window. Text contained in these components will be read by assistive
- * devices when it is opened.
- *
- * @param components
- * the components to use as description
- */
- public void setAssistiveDescription(Component... components) {
- if (components == null) {
- throw new IllegalArgumentException(
- "Parameter connectors must be non-null");
- } else {
- getState().contentDescription = components;
- }
- }
-
- /**
- * Gets the components that are used as assistive description. Text
- * contained in these components will be read by assistive devices when the
- * window is opened.
- *
- * @return array of previously set components
- */
- public Component[] getAssistiveDescription() {
- Connector[] contentDescription = getState(false).contentDescription;
- if (contentDescription == null) {
- return null;
- }
-
- Component[] target = new Component[contentDescription.length];
- System.arraycopy(contentDescription, 0, target, 0,
- contentDescription.length);
-
- return target;
- }
-
- /**
- * Sets the accessibility prefix for the window caption.
- *
- * This prefix is read to assistive device users before the window caption,
- * but not visible on the page.
- *
- * @param prefix
- * String that is placed before the window caption
- */
- public void setAssistivePrefix(String prefix) {
- getState().assistivePrefix = prefix;
- }
-
- /**
- * Gets the accessibility prefix for the window caption.
- *
- * This prefix is read to assistive device users before the window caption,
- * but not visible on the page.
- *
- * @return The accessibility prefix
- */
- public String getAssistivePrefix() {
- return getState(false).assistivePrefix;
- }
-
- /**
- * Sets the accessibility postfix for the window caption.
- *
- * This postfix is read to assistive device users after the window caption,
- * but not visible on the page.
- *
- * @param assistivePostfix
- * String that is placed after the window caption
- */
- public void setAssistivePostfix(String assistivePostfix) {
- getState().assistivePostfix = assistivePostfix;
- }
-
- /**
- * Gets the accessibility postfix for the window caption.
- *
- * This postfix is read to assistive device users after the window caption,
- * but not visible on the page.
- *
- * @return The accessibility postfix
- */
- public String getAssistivePostfix() {
- return getState(false).assistivePostfix;
- }
-
- /**
- * Sets the WAI-ARIA role the window.
- *
- * This role defines how an assistive device handles a window. Available
- * roles are alertdialog and dialog (@see
- * <a href="http://www.w3.org/TR/2011/CR-wai-aria-20110118/roles">Roles
- * Model</a>).
- *
- * The default role is dialog.
- *
- * @param role
- * WAI-ARIA role to set for the window
- */
- public void setAssistiveRole(WindowRole role) {
- getState().role = role;
- }
-
- /**
- * Gets the WAI-ARIA role the window.
- *
- * This role defines how an assistive device handles a window. Available
- * roles are alertdialog and dialog (@see
- * <a href="http://www.w3.org/TR/2011/CR-wai-aria-20110118/roles">Roles
- * Model</a>).
- *
- * @return WAI-ARIA role set for the window
- */
- public WindowRole getAssistiveRole() {
- return getState(false).role;
- }
-
- /**
- * Set if it should be prevented to set the focus to a component outside a
- * non-modal window with the tab key.
- * <p>
- * This is meant to help users of assistive devices to not leaving the
- * window unintentionally.
- * <p>
- * For modal windows, this function is activated automatically, while
- * preserving the stored value of tabStop.
- *
- * @param tabStop
- * true to keep the focus inside the window when reaching the top
- * or bottom, false (default) to allow leaving the window
- */
- public void setTabStopEnabled(boolean tabStop) {
- getState().assistiveTabStop = tabStop;
- }
-
- /**
- * Get if it is prevented to leave a window with the tab key.
- *
- * @return true when the focus is limited to inside the window, false when
- * focus can leave the window
- */
- public boolean isTabStopEnabled() {
- return getState(false).assistiveTabStop;
- }
-
- /**
- * Sets the message that is provided to users of assistive devices when the
- * user reaches the top of the window when leaving a window with the tab key
- * is prevented.
- * <p>
- * This message is not visible on the screen.
- *
- * @param topMessage
- * String provided when the user navigates with Shift-Tab keys to
- * the top of the window
- */
- public void setTabStopTopAssistiveText(String topMessage) {
- getState().assistiveTabStopTopText = topMessage;
- }
-
- /**
- * Sets the message that is provided to users of assistive devices when the
- * user reaches the bottom of the window when leaving a window with the tab
- * key is prevented.
- * <p>
- * This message is not visible on the screen.
- *
- * @param bottomMessage
- * String provided when the user navigates with the Tab key to
- * the bottom of the window
- */
- public void setTabStopBottomAssistiveText(String bottomMessage) {
- getState().assistiveTabStopBottomText = bottomMessage;
- }
-
- /**
- * Gets the message that is provided to users of assistive devices when the
- * user reaches the top of the window when leaving a window with the tab key
- * is prevented.
- *
- * @return the top message
- */
- public String getTabStopTopAssistiveText() {
- return getState(false).assistiveTabStopTopText;
- }
-
- /**
- * Gets the message that is provided to users of assistive devices when the
- * user reaches the bottom of the window when leaving a window with the tab
- * key is prevented.
- *
- * @return the bottom message
- */
- public String getTabStopBottomAssistiveText() {
- return getState(false).assistiveTabStopBottomText;
- }
-
- @Override
- public void readDesign(Element design, DesignContext context) {
- super.readDesign(design, context);
-
- if (design.hasAttr("center")) {
- center();
- }
- if (design.hasAttr("position")) {
- String[] position = design.attr("position").split(",");
- setPositionX(Integer.parseInt(position[0]));
- setPositionY(Integer.parseInt(position[1]));
- }
-
- // Parse shortcuts if defined, otherwise rely on default behavior
- if (design.hasAttr("close-shortcut")) {
-
- // Parse shortcuts
- String[] shortcutStrings = DesignAttributeHandler
- .readAttribute("close-shortcut", design.attributes(),
- String.class)
- .split("\\s+");
-
- removeAllCloseShortcuts();
-
- for (String part : shortcutStrings) {
- if (!part.isEmpty()) {
- ShortcutAction shortcut = DesignAttributeHandler
- .getFormatter()
- .parse(part.trim(), ShortcutAction.class);
- addCloseShortcut(shortcut.getKeyCode(),
- shortcut.getModifiers());
- }
- }
- }
- }
-
- /**
- * Reads the content and possible assistive descriptions from the list of
- * child elements of a design. If an element has an
- * {@code :assistive-description} attribute, adds the parsed component to
- * the list of components used as the assistive description of this Window.
- * Otherwise, sets the component as the content of this Window. If there are
- * multiple non-description elements, throws a DesignException.
- *
- * @param children
- * child elements in a design
- * @param context
- * the DesignContext instance used to parse the design
- *
- * @throws DesignException
- * if there are multiple non-description child elements
- * @throws DesignException
- * if a child element could not be parsed as a Component
- *
- * @see #setContent(Component)
- * @see #setAssistiveDescription(Component...)
- */
- @Override
- protected void readDesignChildren(Elements children,
- DesignContext context) {
- List<Component> descriptions = new ArrayList<>();
- Elements content = new Elements();
-
- for (Element child : children) {
- if (child.hasAttr(":assistive-description")) {
- descriptions.add(context.readDesign(child));
- } else {
- content.add(child);
- }
- }
- super.readDesignChildren(content, context);
- setAssistiveDescription(
- descriptions.toArray(new Component[descriptions.size()]));
- }
-
- @Override
- public void writeDesign(Element design, DesignContext context) {
- super.writeDesign(design, context);
-
- Window def = context.getDefaultInstance(this);
-
- if (getState().centered) {
- design.attr("center", true);
- }
-
- DesignAttributeHandler.writeAttribute("position", design.attributes(),
- getPosition(), def.getPosition(), String.class, context);
-
- // Process keyboard shortcuts
- if (closeShortcuts.size() == 1 && hasCloseShortcut(KeyCode.ESCAPE)) {
- // By default, we won't write anything if we're relying on default
- // shortcut behavior
- } else {
- // Dump all close shortcuts to a string...
- String attrString = "";
-
- // TODO: add canonical support for array data in XML attributes
- for (CloseShortcut shortcut : closeShortcuts) {
- String shortcutString = DesignAttributeHandler.getFormatter()
- .format(shortcut, CloseShortcut.class);
- attrString += shortcutString + " ";
- }
-
- // Write everything except the last "," to the design
- DesignAttributeHandler.writeAttribute("close-shortcut",
- design.attributes(), attrString.trim(), null, String.class,
- context);
- }
-
- for (Component c : getAssistiveDescription()) {
- Element child = context.createElement(c)
- .attr(":assistive-description", true);
- design.appendChild(child);
- }
- }
-
- private String getPosition() {
- return getPositionX() + "," + getPositionY();
- }
-
- @Override
- protected Collection<String> getCustomAttributes() {
- Collection<String> result = super.getCustomAttributes();
- result.add("center");
- result.add("position");
- result.add("position-y");
- result.add("position-x");
- result.add("close-shortcut");
- return result;
- }
- }
|