Browse Source

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

Change-Id: I259c659987b5b15b354e16d0be1523f4ede809f0
tags/8.0.0.alpha8
Denis Anisimov 7 years ago
parent
commit
8ba529503b

+ 64
- 8
client/src/main/java/com/vaadin/client/ui/VWindow.java View File

@@ -44,6 +44,7 @@ import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.ScrollEvent;
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.user.client.Command;
import com.google.gwt.user.client.DOM;
@@ -64,6 +65,8 @@ import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
import com.vaadin.client.ui.aria.AriaHelper;
import com.vaadin.client.ui.window.WindowMoveEvent;
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.EventId;
import com.vaadin.shared.ui.window.WindowMode;
@@ -79,6 +82,9 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,

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

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

private static boolean orderingDefered;

public static final String CLASSNAME = "v-window";
@@ -278,14 +284,37 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
}

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

private void bringToFront(boolean notifyListeners) {
int curIndex = getWindowOrder();
if (curIndex + 1 < windowOrder.size()) {
windowOrder.remove(this);
windowOrder.add(this);
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)));
}

/**
@@ -317,13 +346,22 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
windowOrder.add(this);
setPopupPosition(order * STACKING_OFFSET_PIXELS,
order * STACKING_OFFSET_PIXELS);
doFireOrderEvent();
}

private void setWindowOrder(int order) {
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
protected void setZIndex(int zIndex) {
super.setZIndex(zIndex);
@@ -536,7 +574,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
for (int i = 0; i < array.length; i++) {
VWindow w = array[i];
if (w.bringToFrontSequence != -1 || w.vaadinModality) {
w.bringToFront();
w.bringToFront(false);
w.bringToFrontSequence = -1;
}
}
@@ -548,6 +586,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
if (topmost != null && topmost.vaadinModality) {
topmost.focus();
}
fireOrderEvent();
}

@Override
@@ -655,15 +694,21 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
}
super.hide();

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

/** For internal use only. May be removed or replaced in the future. */
@@ -689,8 +734,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
}

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

if (isShowing()) {
getOverlayContainer().insertBefore(getModalityCurtain(),
@@ -1463,4 +1507,16 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
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 View File

@@ -16,6 +16,11 @@
package com.vaadin.client.ui.ui;

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.List;
import java.util.logging.Logger;
@@ -75,14 +80,19 @@ import com.vaadin.client.ui.VUI;
import com.vaadin.client.ui.VWindow;
import com.vaadin.client.ui.layout.MayScrollChildren;
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.shared.ApplicationConstants;
import com.vaadin.shared.Connector;
import com.vaadin.shared.EventId;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.Version;
import com.vaadin.shared.communication.MethodInvocation;
import com.vaadin.shared.ui.ComponentStateUtil;
import com.vaadin.shared.ui.Connect;
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.DebugWindowServerRpc;
import com.vaadin.shared.ui.ui.PageClientRpc;
@@ -103,6 +113,8 @@ public class UIConnector extends AbstractSingleComponentContainerConnector

private String activeTheme = null;

private HandlerRegistration windowOrderRegistration;

private final StateChangeHandler childStateChangeHandler = new StateChangeHandler() {
@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
@@ -112,9 +124,33 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
}
};

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
protected void init() {
super.init();
windowOrderRegistration = VWindow
.addWindowOrderHandler(windowOrderHandler);
registerRpc(PageClientRpc.class, new PageClientRpc() {

@Override
@@ -703,6 +739,8 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
}
}

setWindowOrderAndPosition();

// Close removed sub windows
for (ComponentConnector c : event.getOldChildren()) {
if (c.getParent() != this && c instanceof WindowConnector) {
@@ -1124,4 +1162,50 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
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 View File

@@ -38,7 +38,6 @@ import com.vaadin.client.ConnectorHierarchyChangeEvent;
import com.vaadin.client.LayoutManager;
import com.vaadin.client.Paintable;
import com.vaadin.client.UIDL;
import com.vaadin.client.communication.RpcProxy;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractSingleComponentContainerConnector;
import com.vaadin.client.ui.ClickEventHandler;
@@ -497,8 +496,7 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector

@Override
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 View File

@@ -0,0 +1,74 @@
/*
* 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 View File

@@ -0,0 +1,36 @@
/*
* 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 View File

@@ -18,14 +18,18 @@ package com.vaadin.ui;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -34,6 +38,7 @@ import com.vaadin.annotations.PreserveOnRefresh;
import com.vaadin.event.Action;
import com.vaadin.event.Action.Handler;
import com.vaadin.event.ActionManager;
import com.vaadin.event.ConnectorEventListener;
import com.vaadin.event.MouseEvents.ClickEvent;
import com.vaadin.event.MouseEvents.ClickListener;
import com.vaadin.event.UIEvents.PollEvent;
@@ -62,6 +67,7 @@ import com.vaadin.shared.EventId;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.Registration;
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.DebugWindowServerRpc;
import com.vaadin.shared.ui.ui.ScrollClientRpc;
@@ -70,9 +76,11 @@ import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.shared.ui.ui.UIServerRpc;
import com.vaadin.shared.ui.ui.UIState;
import com.vaadin.ui.Component.Focusable;
import com.vaadin.ui.Window.WindowOrderChangeListener;
import com.vaadin.ui.declarative.Design;
import com.vaadin.util.ConnectorHelper;
import com.vaadin.util.CurrentInstance;
import com.vaadin.util.ReflectTools;

/**
* The topmost component in any component hierarchy. There is one UI for every
@@ -245,6 +253,21 @@ public abstract class UI extends AbstractSingleComponentContainer
}
};

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
* current time whenever the application receives a heartbeat or UIDL
@@ -290,6 +313,7 @@ public abstract class UI extends AbstractSingleComponentContainer
public UI(Component content) {
registerRpc(rpc);
registerRpc(debugRpc);
registerRpc(windowOrderRpc);
setSizeFull();
setContent(content);
}
@@ -387,6 +411,19 @@ public abstract class UI extends AbstractSingleComponentContainer
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
@SuppressWarnings("unchecked")
public void changeVariables(Object source, Map<String, Object> variables) {
@@ -569,6 +606,7 @@ public abstract class UI extends AbstractSingleComponentContainer
markAsDirty();
window.fireClose();
fireComponentDetachEvent(window);
fireWindowOrder(Collections.singletonMap(-1, window));

return true;
}
@@ -1728,4 +1766,88 @@ public abstract class UI extends AbstractSingleComponentContainer
int 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 View File

@@ -28,6 +28,7 @@ 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;
@@ -42,6 +43,7 @@ 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;
@@ -109,6 +111,15 @@ public class Window extends Panel
*/
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
*/
@@ -317,6 +328,24 @@ public class Window extends Panel
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
* containing (main window). Has effect only if in {@link WindowMode#NORMAL}
@@ -365,6 +394,96 @@ public class Window extends Panel
}
}

/**
* 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
* CloseListener to a window and

+ 1
- 0
shared/src/main/java/com/vaadin/shared/EventId.java View File

@@ -25,4 +25,5 @@ public interface EventId extends Serializable {
public static final String POLL = "poll";
public static final String CHANGE = "change";
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 View File

@@ -0,0 +1,41 @@
/*
* 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 View File

@@ -0,0 +1,175 @@
/*
* 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 View File

@@ -0,0 +1,182 @@
/*
* 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");
}

}

Loading…
Cancel
Save