Parcourir la source

Provide access to window order position in windows stack (#14325).

Change-Id: I259c659987b5b15b354e16d0be1523f4ede809f0
tags/8.0.0.alpha8
Denis Anisimov il y a 7 ans
Parent
révision
8ba529503b

+ 64
- 8
client/src/main/java/com/vaadin/client/ui/VWindow.java Voir le fichier

import com.google.gwt.event.dom.client.KeyDownHandler; import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.ScrollEvent; import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler; import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.DOM;
import com.vaadin.client.ui.aria.AriaHelper; import com.vaadin.client.ui.aria.AriaHelper;
import com.vaadin.client.ui.window.WindowMoveEvent; import com.vaadin.client.ui.window.WindowMoveEvent;
import com.vaadin.client.ui.window.WindowMoveHandler; import com.vaadin.client.ui.window.WindowMoveHandler;
import com.vaadin.client.ui.window.WindowOrderEvent;
import com.vaadin.client.ui.window.WindowOrderHandler;
import com.vaadin.shared.Connector; import com.vaadin.shared.Connector;
import com.vaadin.shared.EventId; import com.vaadin.shared.EventId;
import com.vaadin.shared.ui.window.WindowMode; import com.vaadin.shared.ui.window.WindowMode;


private static ArrayList<VWindow> windowOrder = new ArrayList<>(); private static ArrayList<VWindow> windowOrder = new ArrayList<>();


private static HandlerManager WINDOW_ORDER_HANDLER = new HandlerManager(
VWindow.class);

private static boolean orderingDefered; private static boolean orderingDefered;


public static final String CLASSNAME = "v-window"; public static final String CLASSNAME = "v-window";
} }


public void bringToFront() { public void bringToFront() {
int curIndex = windowOrder.indexOf(this);
bringToFront(true);
}

private void bringToFront(boolean notifyListeners) {
int curIndex = getWindowOrder();
if (curIndex + 1 < windowOrder.size()) { if (curIndex + 1 < windowOrder.size()) {
windowOrder.remove(this); windowOrder.remove(this);
windowOrder.add(this); windowOrder.add(this);
for (; curIndex < windowOrder.size(); curIndex++) { for (; curIndex < windowOrder.size(); curIndex++) {
windowOrder.get(curIndex).setWindowOrder(curIndex);
VWindow window = windowOrder.get(curIndex);
window.setWindowOrder(curIndex);
} }
} }
if (notifyListeners) {
fireOrderEvent();
}
}

static void fireOrderEvent() {
fireOrderEvent(windowOrder);
}

private void doFireOrderEvent() {
ArrayList<VWindow> list = new ArrayList<>();
list.add(this);
fireOrderEvent(list);
}

private static void fireOrderEvent(ArrayList<VWindow> windows) {
WINDOW_ORDER_HANDLER
.fireEvent(new WindowOrderEvent(new ArrayList<>(windows)));
} }


/** /**
windowOrder.add(this); windowOrder.add(this);
setPopupPosition(order * STACKING_OFFSET_PIXELS, setPopupPosition(order * STACKING_OFFSET_PIXELS,
order * STACKING_OFFSET_PIXELS); order * STACKING_OFFSET_PIXELS);
doFireOrderEvent();
} }


private void setWindowOrder(int order) { private void setWindowOrder(int order) {
setZIndex(order + Z_INDEX); setZIndex(order + Z_INDEX);
} }


/**
* Returns window position in list of opened and shown windows.
*
* @since 8.0.0
*/
public final int getWindowOrder() {
return windowOrder.indexOf(this);
}

@Override @Override
protected void setZIndex(int zIndex) { protected void setZIndex(int zIndex) {
super.setZIndex(zIndex); super.setZIndex(zIndex);
for (int i = 0; i < array.length; i++) { for (int i = 0; i < array.length; i++) {
VWindow w = array[i]; VWindow w = array[i];
if (w.bringToFrontSequence != -1 || w.vaadinModality) { if (w.bringToFrontSequence != -1 || w.vaadinModality) {
w.bringToFront();
w.bringToFront(false);
w.bringToFrontSequence = -1; w.bringToFrontSequence = -1;
} }
} }
if (topmost != null && topmost.vaadinModality) { if (topmost != null && topmost.vaadinModality) {
topmost.focus(); topmost.focus();
} }
fireOrderEvent();
} }


@Override @Override
} }
super.hide(); super.hide();


int curIndex = windowOrder.indexOf(this);
int curIndex = getWindowOrder();
// Remove window from windowOrder to avoid references being left // Remove window from windowOrder to avoid references being left
// hanging. // hanging.
windowOrder.remove(curIndex); windowOrder.remove(curIndex);
// Update the z-indices of any remaining windows // Update the z-indices of any remaining windows
ArrayList<VWindow> update = new ArrayList<>(
windowOrder.size() - curIndex + 1);
update.add(this);
while (curIndex < windowOrder.size()) { while (curIndex < windowOrder.size()) {
windowOrder.get(curIndex).setWindowOrder(curIndex++);
VWindow window = windowOrder.get(curIndex);
window.setWindowOrder(curIndex++);
update.add(window);
} }
focusTopmostModalWindow(); focusTopmostModalWindow();
fireOrderEvent(update);
} }


/** For internal use only. May be removed or replaced in the future. */ /** For internal use only. May be removed or replaced in the future. */
} }


private void showModalityCurtain() { private void showModalityCurtain() {
getModalityCurtain().getStyle()
.setZIndex(windowOrder.indexOf(this) + Z_INDEX);
getModalityCurtain().getStyle().setZIndex(getWindowOrder() + Z_INDEX);


if (isShowing()) { if (isShowing()) {
getOverlayContainer().insertBefore(getModalityCurtain(), getOverlayContainer().insertBefore(getModalityCurtain(),
return addHandler(handler, WindowMoveEvent.getType()); return addHandler(handler, WindowMoveEvent.getType());
} }


/**
* Adds a Handler for window order change event.
*
* @since 8.0.0
*
* @return registration object to deregister the handler
*/
public static HandlerRegistration addWindowOrderHandler(
WindowOrderHandler handler) {
return WINDOW_ORDER_HANDLER.addHandler(WindowOrderEvent.getType(),
handler);
}
} }

+ 84
- 0
client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java Voir le fichier

package com.vaadin.client.ui.ui; package com.vaadin.client.ui.ui;


import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.vaadin.client.ui.VWindow; import com.vaadin.client.ui.VWindow;
import com.vaadin.client.ui.layout.MayScrollChildren; import com.vaadin.client.ui.layout.MayScrollChildren;
import com.vaadin.client.ui.window.WindowConnector; import com.vaadin.client.ui.window.WindowConnector;
import com.vaadin.client.ui.window.WindowOrderEvent;
import com.vaadin.client.ui.window.WindowOrderHandler;
import com.vaadin.server.Page.Styles; import com.vaadin.server.Page.Styles;
import com.vaadin.shared.ApplicationConstants; import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.Connector;
import com.vaadin.shared.EventId;
import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.Version; import com.vaadin.shared.Version;
import com.vaadin.shared.communication.MethodInvocation; import com.vaadin.shared.communication.MethodInvocation;
import com.vaadin.shared.ui.ComponentStateUtil; import com.vaadin.shared.ui.ComponentStateUtil;
import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.Connect.LoadStyle; import com.vaadin.shared.ui.Connect.LoadStyle;
import com.vaadin.shared.ui.WindowOrderRpc;
import com.vaadin.shared.ui.ui.DebugWindowClientRpc; import com.vaadin.shared.ui.ui.DebugWindowClientRpc;
import com.vaadin.shared.ui.ui.DebugWindowServerRpc; import com.vaadin.shared.ui.ui.DebugWindowServerRpc;
import com.vaadin.shared.ui.ui.PageClientRpc; import com.vaadin.shared.ui.ui.PageClientRpc;


private String activeTheme = null; private String activeTheme = null;


private HandlerRegistration windowOrderRegistration;

private final StateChangeHandler childStateChangeHandler = new StateChangeHandler() { private final StateChangeHandler childStateChangeHandler = new StateChangeHandler() {
@Override @Override
public void onStateChanged(StateChangeEvent stateChangeEvent) { public void onStateChanged(StateChangeEvent stateChangeEvent) {
} }
}; };


private WindowOrderHandler windowOrderHandler = new WindowOrderHandler() {

@Override
public void onWindowOrderChange(WindowOrderEvent event) {
VWindow[] windows = event.getWindows();
HashMap<Integer, Connector> orders = new HashMap<>();
boolean hasEventListener = hasEventListener(EventId.WINDOW_ORDER);
for (VWindow window : windows) {
Connector connector = Util.findConnectorFor(window);
orders.put(window.getWindowOrder(), connector);
if (connector instanceof AbstractConnector
&& ((AbstractConnector) connector)
.hasEventListener(EventId.WINDOW_ORDER)) {
hasEventListener = true;
}
}
if (hasEventListener) {
getRpcProxy(WindowOrderRpc.class).windowOrderChanged(orders);
}
}
};

@Override @Override
protected void init() { protected void init() {
super.init(); super.init();
windowOrderRegistration = VWindow
.addWindowOrderHandler(windowOrderHandler);
registerRpc(PageClientRpc.class, new PageClientRpc() { registerRpc(PageClientRpc.class, new PageClientRpc() {


@Override @Override
} }
} }


setWindowOrderAndPosition();

// Close removed sub windows // Close removed sub windows
for (ComponentConnector c : event.getOldChildren()) { for (ComponentConnector c : event.getOldChildren()) {
if (c.getParent() != this && c instanceof WindowConnector) { if (c.getParent() != this && c instanceof WindowConnector) {
getRpcProxy(UIServerRpc.class).acknowledge(); getRpcProxy(UIServerRpc.class).acknowledge();


} }

private void setWindowOrderAndPosition() {
if (windowOrderRegistration != null) {
windowOrderRegistration.removeHandler();
}
WindowOrderCollector collector = new WindowOrderCollector();
HandlerRegistration registration = VWindow
.addWindowOrderHandler(collector);
for (ComponentConnector c : getChildComponents()) {
if (c instanceof WindowConnector) {
WindowConnector wc = (WindowConnector) c;
wc.setWindowOrderAndPosition();
}
}
windowOrderHandler.onWindowOrderChange(
new WindowOrderEvent(collector.getWindows()));
registration.removeHandler();
windowOrderRegistration = VWindow
.addWindowOrderHandler(windowOrderHandler);
}

private static class WindowOrderCollector
implements WindowOrderHandler, Comparator<VWindow> {

private HashSet<VWindow> windows = new HashSet<>();

@Override
public void onWindowOrderChange(WindowOrderEvent event) {
windows.addAll(Arrays.asList(event.getWindows()));
}

@Override
public int compare(VWindow window1, VWindow window2) {
if (window1.getWindowOrder() == window2.getWindowOrder()) {
return 0;
}
return window1.getWindowOrder() > window2.getWindowOrder() ? 1 : -1;
}

ArrayList<VWindow> getWindows() {
ArrayList<VWindow> result = new ArrayList<>();
result.addAll(windows);
Collections.sort(result, this);
return result;
}
};
} }

+ 2
- 4
client/src/main/java/com/vaadin/client/ui/window/WindowConnector.java Voir le fichier

import com.vaadin.client.LayoutManager; import com.vaadin.client.LayoutManager;
import com.vaadin.client.Paintable; import com.vaadin.client.Paintable;
import com.vaadin.client.UIDL; import com.vaadin.client.UIDL;
import com.vaadin.client.communication.RpcProxy;
import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractSingleComponentContainerConnector; import com.vaadin.client.ui.AbstractSingleComponentContainerConnector;
import com.vaadin.client.ui.ClickEventHandler; import com.vaadin.client.ui.ClickEventHandler;


@Override @Override
public void onWindowMove(WindowMoveEvent event) { public void onWindowMove(WindowMoveEvent event) {
RpcProxy.create(WindowServerRpc.class, this)
.windowMoved(event.getNewX(), event.getNewY());

getRpcProxy(WindowServerRpc.class).windowMoved(event.getNewX(),
event.getNewY());
} }
} }

+ 74
- 0
client/src/main/java/com/vaadin/client/ui/window/WindowOrderEvent.java Voir le fichier

/*
* 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.client.ui.window;

import java.util.ArrayList;

import com.google.gwt.event.shared.GwtEvent;
import com.vaadin.client.ui.VWindow;

/**
* Event for window order position updates.
*
* @since 8.0.0
*
* @author Vaadin Ltd
*/
public class WindowOrderEvent extends GwtEvent<WindowOrderHandler> {

private static final Type<WindowOrderHandler> TYPE = new Type<>();

private final ArrayList<VWindow> windows;

/**
* Creates a new event with the given order.
*
* @param windows
* The new order position for the VWindow
*/
public WindowOrderEvent(ArrayList<VWindow> windows) {
this.windows = windows;
}

@Override
public Type<WindowOrderHandler> getAssociatedType() {
return TYPE;
}

/**
* Returns windows in order.
*
* @return windows in the specific order
*/
public VWindow[] getWindows() {
return windows.toArray(new VWindow[windows.size()]);
}

@Override
protected void dispatch(WindowOrderHandler handler) {
handler.onWindowOrderChange(this);
}

/**
* Gets the type of the event.
*
* @return the type of the event
*/
public static Type<WindowOrderHandler> getType() {
return TYPE;
}

}

+ 36
- 0
client/src/main/java/com/vaadin/client/ui/window/WindowOrderHandler.java Voir le fichier

/*
* 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.client.ui.window;

import com.google.gwt.event.shared.EventHandler;

/**
* Handler for {@link WindowOrderEvent}s.
*
* @since 8.0.0
*
* @author Vaadin Ltd
*/
public interface WindowOrderHandler extends EventHandler {

/**
* Called when the VWindow instances changed their order position.
*
* @param event
* Contains windows whose position has changed
*/
public void onWindowOrderChange(WindowOrderEvent event);
}

+ 122
- 0
server/src/main/java/com/vaadin/ui/UI.java Voir le fichier



import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI; import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.vaadin.event.Action; import com.vaadin.event.Action;
import com.vaadin.event.Action.Handler; import com.vaadin.event.Action.Handler;
import com.vaadin.event.ActionManager; import com.vaadin.event.ActionManager;
import com.vaadin.event.ConnectorEventListener;
import com.vaadin.event.MouseEvents.ClickEvent; import com.vaadin.event.MouseEvents.ClickEvent;
import com.vaadin.event.MouseEvents.ClickListener; import com.vaadin.event.MouseEvents.ClickListener;
import com.vaadin.event.UIEvents.PollEvent; import com.vaadin.event.UIEvents.PollEvent;
import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.Registration; import com.vaadin.shared.Registration;
import com.vaadin.shared.communication.PushMode; import com.vaadin.shared.communication.PushMode;
import com.vaadin.shared.ui.WindowOrderRpc;
import com.vaadin.shared.ui.ui.DebugWindowClientRpc; import com.vaadin.shared.ui.ui.DebugWindowClientRpc;
import com.vaadin.shared.ui.ui.DebugWindowServerRpc; import com.vaadin.shared.ui.ui.DebugWindowServerRpc;
import com.vaadin.shared.ui.ui.ScrollClientRpc; import com.vaadin.shared.ui.ui.ScrollClientRpc;
import com.vaadin.shared.ui.ui.UIServerRpc; import com.vaadin.shared.ui.ui.UIServerRpc;
import com.vaadin.shared.ui.ui.UIState; import com.vaadin.shared.ui.ui.UIState;
import com.vaadin.ui.Component.Focusable; import com.vaadin.ui.Component.Focusable;
import com.vaadin.ui.Window.WindowOrderChangeListener;
import com.vaadin.ui.declarative.Design; import com.vaadin.ui.declarative.Design;
import com.vaadin.util.ConnectorHelper; import com.vaadin.util.ConnectorHelper;
import com.vaadin.util.CurrentInstance; import com.vaadin.util.CurrentInstance;
import com.vaadin.util.ReflectTools;


/** /**
* The topmost component in any component hierarchy. There is one UI for every * The topmost component in any component hierarchy. There is one UI for every
} }
}; };


private WindowOrderRpc windowOrderRpc = new WindowOrderRpc() {

@Override
public void windowOrderChanged(
HashMap<Integer, Connector> windowOrders) {
Map<Integer, Window> orders = new LinkedHashMap<>();
for (Entry<Integer, Connector> entry : windowOrders.entrySet()) {
if (entry.getValue() instanceof Window) {
orders.put(entry.getKey(), (Window) entry.getValue());
}
}
fireWindowOrder(orders);
}
};

/** /**
* Timestamp keeping track of the last heartbeat of this UI. Updated to the * Timestamp keeping track of the last heartbeat of this UI. Updated to the
* current time whenever the application receives a heartbeat or UIDL * current time whenever the application receives a heartbeat or UIDL
public UI(Component content) { public UI(Component content) {
registerRpc(rpc); registerRpc(rpc);
registerRpc(debugRpc); registerRpc(debugRpc);
registerRpc(windowOrderRpc);
setSizeFull(); setSizeFull();
setContent(content); setContent(content);
} }
fireEvent(new ClickEvent(this, mouseDetails)); fireEvent(new ClickEvent(this, mouseDetails));
} }


/**
* Fire a window order event.
*
* @param windows
* The windows with their orders whose order has been updated.
*/
private void fireWindowOrder(Map<Integer, Window> windows) {
for (Entry<Integer, Window> entry : windows.entrySet()) {
entry.getValue().fireWindowOrderChange(entry.getKey());
}
fireEvent(new WindowOrderUpdateEvent(this, windows.values()));
}

@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void changeVariables(Object source, Map<String, Object> variables) { public void changeVariables(Object source, Map<String, Object> variables) {
markAsDirty(); markAsDirty();
window.fireClose(); window.fireClose();
fireComponentDetachEvent(window); fireComponentDetachEvent(window);
fireWindowOrder(Collections.singletonMap(-1, window));


return true; return true;
} }
int lastProcessedClientToServerId) { int lastProcessedClientToServerId) {
this.lastProcessedClientToServerId = lastProcessedClientToServerId; this.lastProcessedClientToServerId = lastProcessedClientToServerId;
} }

/**
* Adds a WindowOrderUpdateListener to the UI.
* <p>
* The WindowOrderUpdateEvent is fired when the order positions of windows
* are updated. It can happen when some window (this or other) is brought to
* front or detached.
* <p>
* The other way to listen window position for specific window is
* {@link Window#addWindowOrderChangeListener(WindowOrderChangeListener)}
*
* @see Window#addWindowOrderChangeListener(WindowOrderChangeListener)
*
* @param listener
* the WindowModeChangeListener to add.
* @since 8.0.0
*
* @return a registration object for removing the listener
*/
public Registration addWindowOrderUpdateListener(
WindowOrderUpdateListener listener) {
addListener(EventId.WINDOW_ORDER, WindowOrderUpdateEvent.class,
listener, WindowOrderUpdateListener.windowOrderUpdateMethod);
return () -> removeListener(EventId.WINDOW_ORDER,
WindowOrderUpdateEvent.class, listener);
}

/**
* Event which is fired when the ordering of the windows is updated.
* <p>
* The other way to listen window position for specific window is
* {@link Window#addWindowOrderChangeListener(WindowOrderChangeListener)}
*
* @see Window.WindowOrderChangeEvent
*
* @author Vaadin Ltd
* @since 8.0.0
*
*/
public static class WindowOrderUpdateEvent extends Component.Event {

private final Collection<Window> windows;

public WindowOrderUpdateEvent(Component source,
Collection<Window> windows) {
super(source);
this.windows = windows;
}

/**
* Gets the windows in the order they appear in the UI: top most window
* is first, bottom one last.
*
* @return the windows collection
*/
public Collection<Window> getWindows() {
return windows;
}
}

/**
* An interface used for listening to Windows order update events.
*
* @since 8.0.0
*
* @see Window.WindowOrderChangeEvent
*/
public interface WindowOrderUpdateListener extends ConnectorEventListener {

public static final Method windowOrderUpdateMethod = ReflectTools
.findMethod(WindowOrderUpdateListener.class,
"windowOrderUpdated", WindowOrderUpdateEvent.class);

/**
* Called when the windows order positions are changed. Use
* {@link WindowOrderUpdateEvent#getWindows()} to get a reference to the
* {@link Window}s whose order positions are updated. Use
* {@link Window#getOrderPosition()} to get window position for specific
* window.
*
* @param event
*/
public void windowOrderUpdated(WindowOrderUpdateEvent event);
}
} }

+ 119
- 0
server/src/main/java/com/vaadin/ui/Window.java Voir le fichier

import org.jsoup.nodes.Element; import org.jsoup.nodes.Element;
import org.jsoup.select.Elements; import org.jsoup.select.Elements;


import com.vaadin.event.ConnectorEventListener;
import com.vaadin.event.FieldEvents.BlurEvent; import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener; import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.BlurNotifier; import com.vaadin.event.FieldEvents.BlurNotifier;
import com.vaadin.server.PaintException; import com.vaadin.server.PaintException;
import com.vaadin.server.PaintTarget; import com.vaadin.server.PaintTarget;
import com.vaadin.shared.Connector; import com.vaadin.shared.Connector;
import com.vaadin.shared.EventId;
import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.Registration; import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.window.WindowMode; import com.vaadin.shared.ui.window.WindowMode;
*/ */
private List<CloseShortcut> closeShortcuts = new ArrayList<>(4); 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 * Creates a new, empty window
*/ */
return getState(false).positionY; 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.0
*
* @return window order position.
*/
public int getOrderPosition() {
return orderPosition;
}

/** /**
* Sets the distance of Window top border in pixels from top border of the * 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} * containing (main window). Has effect only if in {@link WindowMode#NORMAL}
} }
} }


/**
* 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
*/
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.
*/
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 || this.orderPosition != order) {
this.orderPosition = (order == null) ? -1 : order;
fireEvent(new Window.WindowOrderChangeEvent(this,
getOrderPosition()));
}
}

/** /**
* An interface used for listening to Window close events. Add the * An interface used for listening to Window close events. Add the
* CloseListener to a window and * CloseListener to a window and

+ 1
- 0
shared/src/main/java/com/vaadin/shared/EventId.java Voir le fichier

public static final String POLL = "poll"; public static final String POLL = "poll";
public static final String CHANGE = "change"; public static final String CHANGE = "change";
public static final String CONTEXT_CLICK = "cClick"; public static final String CONTEXT_CLICK = "cClick";
public static final String WINDOW_ORDER = "windowOrder";
} }

+ 41
- 0
shared/src/main/java/com/vaadin/shared/ui/WindowOrderRpc.java Voir le fichier

/*
* 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.shared.ui;

import java.util.HashMap;

import com.vaadin.shared.Connector;
import com.vaadin.shared.communication.ServerRpc;

/**
* Window order RPC interface.
* <p>
* Notifies server when windows order is changed.
*
* @author Vaadin Ltd
* @since 8.0.0
*
*/
public interface WindowOrderRpc extends ServerRpc {

/**
* Sends RPC request about windows order change.
*
* @param windowOrders
* new windows order
*/
void windowOrderChanged(HashMap<Integer, Connector> windowOrders);
}

+ 175
- 0
uitest/src/main/java/com/vaadin/tests/components/window/WindowOrder.java Voir le fichier

/*
* Copyright 2000-2014 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.tests.components.window;

import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Label;
import com.vaadin.ui.Window;
import com.vaadin.ui.Window.WindowOrderChangeEvent;
import com.vaadin.ui.Window.WindowOrderChangeListener;

/**
* Test UI for accessing to window order position.
*
* @author Vaadin Ltd
*/
public class WindowOrder extends AbstractTestUI {

@Override
protected void setup(VaadinRequest request) {
w1 = new Window();
w1.setCaption("Window1");
w1.addStyleName("window1");

w2 = new Window();
w2.setCaption("Window2");
w2.addStyleName("window2");

w3 = new Window();
w3.setCaption("Window3");
w3.addStyleName("window3");

getUI().addWindow(w1);
getUI().addWindow(w2);
getUI().addWindow(w3);
OrderListener listener = new OrderListener();
for (Window window : getUI().getWindows()) {
window.addWindowOrderChangeListener(listener);
}

w4 = new Window();
w4.setCaption("Window4");
w4.addStyleName("window4");
w4.addWindowOrderChangeListener(listener);

infoLabel = createLabel("info-label");
uiLabel = createLabel("ui-label");

getUI().addWindowOrderUpdateListener(new WindowOrderListener());

addComponent(infoLabel);
addComponent(uiLabel);

Button first = new Button("Bring first to front", new ClickListener() {

@Override
public void buttonClick(ClickEvent event) {
w1.bringToFront();
}
});
first.addStyleName("bring-to-front-first");
addComponent(first);
getLayout().setComponentAlignment(first, Alignment.MIDDLE_RIGHT);

Button all = new Button("Bring to front all windows",
new ClickListener() {

@Override
public void buttonClick(ClickEvent event) {
w3.bringToFront();
w1.bringToFront();
w2.bringToFront();
}
});
all.addStyleName("bring-to-front-all");
addComponent(all);
getLayout().setComponentAlignment(all, Alignment.MIDDLE_RIGHT);

Button detach = new Button("Detach last window", new ClickListener() {

@Override
public void buttonClick(ClickEvent event) {
getUI().removeWindow(w3);
}
});
detach.addStyleName("detach-window");
addComponent(detach);
getLayout().setComponentAlignment(detach, Alignment.MIDDLE_RIGHT);

Button add = new Button("Add new window", new ClickListener() {

@Override
public void buttonClick(ClickEvent event) {
getUI().addWindow(w4);
}
});
add.addStyleName("add-window");
addComponent(add);
getLayout().setComponentAlignment(add, Alignment.MIDDLE_RIGHT);
}

@Override
protected String getTestDescription() {
return "Window order position access and listeners for order change events.";
}

@Override
protected Integer getTicketNumber() {
return 14325;
}

private Label createLabel(String style) {
Label label = new Label();
label.addStyleName(style);
return label;
}

private class OrderListener implements WindowOrderChangeListener {

@Override
public void windowOrderChanged(WindowOrderChangeEvent event) {
infoLabel.removeStyleName("w4--1");
infoLabel.addStyleName("w4-" + w4.getOrderPosition());

if (event.getWindow() == w3 && event.getOrder() == -1) {
Label detached = new Label("Window 3 is detached");
detached.addStyleName("w3-detached");
detached.addStyleName("w3-" + w3.getOrderPosition());
addComponent(detached);
}

Window window = event.getWindow();
Label label = new Label(String.valueOf(window.getOrderPosition()));
label.addStyleName("event-order" + event.getOrder());
window.setContent(label);
}
}

private class WindowOrderListener implements WindowOrderUpdateListener {

@Override
public void windowOrderUpdated(WindowOrderUpdateEvent event) {
uiLabel.removeStyleName(infoLabel.getStyleName());
for (Window window : event.getWindows()) {
uiLabel.addStyleName(
window.getStyleName() + "-" + window.getOrderPosition());
}
}
}

private Window w1;
private Window w2;
private Window w3;
private Window w4;
private Label infoLabel;

private Label uiLabel;
}

+ 182
- 0
uitest/src/test/java/com/vaadin/tests/components/window/WindowOrderTest.java Voir le fichier

/*
* Copyright 2000-2014 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.tests.components.window;

import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

import com.vaadin.tests.tb3.MultiBrowserTest;

/**
* Test for window order position access.
*
* @author Vaadin Ltd
*/
public class WindowOrderTest extends MultiBrowserTest {

@Test
public void orderGetterTest() {
openTestURL();

checkPositionsAfterFirstWindowActivation();

checkPositionsAfterActivationThirdFirstSecond();

checkPositionsAfterDetachingThirdWindow();

checkPositionsAfterNewWindowAttach();
}

private void checkPositionsAfterFirstWindowActivation() {
// Bring the first window to front and check order positions of the
// windows
findElement(By.className("bring-to-front-first")).click();
Assert.assertTrue(
"The first window has wrong order position after bring first to front",
hasOrder("window1", 2));
Assert.assertTrue(
"The first window position is incorrectly updated via UI listener after bring first to front",
hasOrderInUi("window1", 2));
Assert.assertTrue(
"The second window has wrong order position after bring first to front",
hasOrder("window2", 0));
Assert.assertTrue(
"The second window position is incorrectly updated via UI after bring first to front",
hasOrderInUi("window2", 0));
Assert.assertTrue(
"The third window has wrong order position after bring first to front",
hasOrder("window3", 1));
Assert.assertTrue(
"The third window position is incorrectly updated via UI after bring first to front",
hasOrderInUi("window3", 1));
Assert.assertTrue(
"Last window is not attached and should have '-1' position, but hasn't.",
lastWindowHasOrder(-1));
}

private void checkPositionsAfterActivationThirdFirstSecond() {
// Bring third, first and second window at once (exactly in this order)
// to front and check order positions of the
// windows
findElement(By.className("bring-to-front-all")).click();

Assert.assertTrue(
"The first window has wrong order position after bring all to front",
hasOrder("window2", 2));
Assert.assertTrue(
"The first window position is incorrectly updated via UI after bring all to front",
hasOrderInUi("window2", 2));
Assert.assertTrue(
"The second window has wrong order position after bring all to front",
hasOrder("window1", 1));
Assert.assertTrue(
"The second window position is incorrectly updated via UI after bring all to front",
hasOrderInUi("window1", 1));
Assert.assertTrue(
"The third window has wrong order position after bring all to front",
hasOrder("window3", 0));
Assert.assertTrue(
"The third window position is incorrectly updated via UI after bring all to front",
hasOrderInUi("window3", 0));
Assert.assertTrue(
"Last window is not attached and should have '-1' position, but hasn't.",
lastWindowHasOrder(-1));
}

private void checkPositionsAfterDetachingThirdWindow() {
// Detach third window and check order positions of the
// windows
findElement(By.className("detach-window")).click();

Assert.assertTrue(
"The first window has wrong order position after detach last window",
hasOrder("window2", 1));
Assert.assertTrue(
"The first window position is incorrectly updated after detach last window",
hasOrderInUi("window2", 1));
Assert.assertTrue(
"The second window has wrong order position after detach last window",
hasOrder("window1", 0));
Assert.assertTrue(
"The second window position is incorrectly updated after detach last window",
hasOrderInUi("window1", 0));
WebElement thirdWindowInfo = findElement(By.className("w3-detached"));
Assert.assertTrue("The third window has wrong order after detach",
thirdWindowInfo.getAttribute("class").contains("w3--1"));
Assert.assertTrue(
"The third window position is incorrectly updated after detach last window",
hasOrderInUi("window3", -1));
Assert.assertTrue(
"Last window is not attached and should have '-1' position, but hasn't.",
lastWindowHasOrder(-1));
}

private void checkPositionsAfterNewWindowAttach() {
// Attach new window and check order positions of the
// windows
findElement(By.className("add-window")).click();

Assert.assertTrue(
"The first window has wrong order position after add new window",
hasOrder("window2", 1));
Assert.assertTrue(
"The first window position is incorrectly updated after add new window",
hasOrderInUi("window2", 1));
Assert.assertTrue(
"The second window has wrong order position after add new window",
hasOrder("window1", 0));
Assert.assertTrue(
"The second window position is incorrectly updated after add new window",
hasOrderInUi("window1", 0));
Assert.assertTrue(
"The last window has wrong order position after add new window",
hasOrder("window4", 2));
Assert.assertTrue(
"The last window position is incorrectly updated after add new window",
hasOrderInUi("window4", 2));
}

private WebElement findElement(String styleName) {
return findElement(By.className(styleName));
}

private boolean hasOrder(String window, int order) {
WebElement win = findElement(window);
WebElement content = win.findElement(By.className("v-label"));
return content.getText().equals(String.valueOf(order)) && content
.getAttribute("class").contains("event-order" + order);
}

private boolean hasOrderInUi(String window, int order) {
WebElement uiLabel = findElement(By.className("ui-label"));
return uiLabel.getAttribute("class").contains(window + '-' + order);
}

private boolean lastWindowHasOrder(int order) {
WebElement info = findElement("info-label");
String clazz = info.getAttribute("class");
String style = "w4-" + order;
boolean hasOrder = clazz.contains(style);
if (!hasOrder) {
return false;
}
clazz = clazz.replace(style, "");
return !clazz.contains("w4");
}

}

Chargement…
Annuler
Enregistrer