Change-Id: Icef0858ee495abcacab7823f7f8fc6044abd64dctags/7.0.0.beta11
@@ -20,6 +20,9 @@ import java.util.ArrayList; | |||
import com.google.gwt.core.client.Scheduler.ScheduledCommand; | |||
import com.google.gwt.dom.client.Element; | |||
import com.google.gwt.event.dom.client.HasScrollHandlers; | |||
import com.google.gwt.event.dom.client.ScrollEvent; | |||
import com.google.gwt.event.dom.client.ScrollHandler; | |||
import com.google.gwt.event.logical.shared.HasResizeHandlers; | |||
import com.google.gwt.event.logical.shared.ResizeEvent; | |||
import com.google.gwt.event.logical.shared.ResizeHandler; | |||
@@ -49,7 +52,7 @@ import com.vaadin.shared.ui.ui.UIConstants; | |||
*/ | |||
public class VUI extends SimplePanel implements ResizeHandler, | |||
Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable, | |||
HasResizeHandlers { | |||
HasResizeHandlers, HasScrollHandlers { | |||
private static int MONITOR_PARENT_TIMER_INTERVAL = 1000; | |||
@@ -94,18 +97,9 @@ public class VUI extends SimplePanel implements ResizeHandler, | |||
/** stored height of parent for embedded application auto-resize */ | |||
private int parentHeight; | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public int scrollTop; | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public int scrollLeft; | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public boolean rendering; | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public boolean scrollable; | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public boolean immediate; | |||
@@ -350,26 +344,6 @@ public class VUI extends SimplePanel implements ResizeHandler, | |||
if (type == Event.ONKEYDOWN && actionHandler != null) { | |||
actionHandler.handleKeyboardEvent(event); | |||
return; | |||
} else if (scrollable && type == Event.ONSCROLL) { | |||
updateScrollPosition(); | |||
} | |||
} | |||
/** | |||
* Updates scroll position from DOM and saves variables to server. | |||
*/ | |||
private void updateScrollPosition() { | |||
int oldTop = scrollTop; | |||
int oldLeft = scrollLeft; | |||
scrollTop = DOM.getElementPropertyInt(getElement(), "scrollTop"); | |||
scrollLeft = DOM.getElementPropertyInt(getElement(), "scrollLeft"); | |||
if (connection != null && !rendering) { | |||
if (oldTop != scrollTop) { | |||
connection.updateVariable(id, "scrollTop", scrollTop, false); | |||
} | |||
if (oldLeft != scrollLeft) { | |||
connection.updateVariable(id, "scrollLeft", scrollLeft, false); | |||
} | |||
} | |||
} | |||
@@ -478,4 +452,9 @@ public class VUI extends SimplePanel implements ResizeHandler, | |||
return addHandler(resizeHandler, ResizeEvent.getType()); | |||
} | |||
@Override | |||
public HandlerRegistration addScrollHandler(ScrollHandler scrollHandler) { | |||
return addHandler(scrollHandler, ScrollEvent.getType()); | |||
} | |||
} |
@@ -23,10 +23,13 @@ import com.google.gwt.core.client.Scheduler; | |||
import com.google.gwt.dom.client.NativeEvent; | |||
import com.google.gwt.dom.client.Style; | |||
import com.google.gwt.dom.client.Style.Position; | |||
import com.google.gwt.event.dom.client.ScrollEvent; | |||
import com.google.gwt.event.dom.client.ScrollHandler; | |||
import com.google.gwt.event.logical.shared.ResizeEvent; | |||
import com.google.gwt.event.logical.shared.ResizeHandler; | |||
import com.google.gwt.user.client.Command; | |||
import com.google.gwt.user.client.DOM; | |||
import com.google.gwt.user.client.Element; | |||
import com.google.gwt.user.client.Event; | |||
import com.google.gwt.user.client.History; | |||
import com.google.gwt.user.client.Window; | |||
@@ -56,6 +59,7 @@ import com.vaadin.shared.ui.ComponentStateUtil; | |||
import com.vaadin.shared.ui.Connect; | |||
import com.vaadin.shared.ui.Connect.LoadStyle; | |||
import com.vaadin.shared.ui.ui.PageClientRpc; | |||
import com.vaadin.shared.ui.ui.ScrollClientRpc; | |||
import com.vaadin.shared.ui.ui.UIConstants; | |||
import com.vaadin.shared.ui.ui.UIServerRpc; | |||
import com.vaadin.shared.ui.ui.UIState; | |||
@@ -85,6 +89,17 @@ public class UIConnector extends AbstractSingleComponentContainerConnector | |||
com.google.gwt.user.client.Window.setTitle(title); | |||
} | |||
}); | |||
registerRpc(ScrollClientRpc.class, new ScrollClientRpc() { | |||
@Override | |||
public void setScrollTop(int scrollTop) { | |||
getWidget().getElement().setScrollTop(scrollTop); | |||
} | |||
@Override | |||
public void setScrollLeft(int scrollLeft) { | |||
getWidget().getElement().setScrollLeft(scrollLeft); | |||
} | |||
}); | |||
getWidget().addResizeHandler(new ResizeHandler() { | |||
@Override | |||
public void onResize(ResizeEvent event) { | |||
@@ -96,6 +111,24 @@ public class UIConnector extends AbstractSingleComponentContainerConnector | |||
} | |||
} | |||
}); | |||
getWidget().addScrollHandler(new ScrollHandler() { | |||
private int lastSentScrollTop = Integer.MAX_VALUE; | |||
private int lastSentScrollLeft = Integer.MAX_VALUE; | |||
@Override | |||
public void onScroll(ScrollEvent event) { | |||
Element element = getWidget().getElement(); | |||
int newScrollTop = element.getScrollTop(); | |||
int newScrollLeft = element.getScrollLeft(); | |||
if (newScrollTop != lastSentScrollTop | |||
|| newScrollLeft != lastSentScrollLeft) { | |||
lastSentScrollTop = newScrollTop; | |||
lastSentScrollLeft = newScrollLeft; | |||
getRpcProxy(UIServerRpc.class).scroll(newScrollTop, | |||
newScrollLeft); | |||
} | |||
} | |||
}); | |||
} | |||
@Override | |||
@@ -244,19 +277,6 @@ public class UIConnector extends AbstractSingleComponentContainerConnector | |||
Window.addResizeHandler(getWidget()); | |||
} | |||
// finally set scroll position from UIDL | |||
if (uidl.hasVariable("scrollTop")) { | |||
getWidget().scrollable = true; | |||
getWidget().scrollTop = uidl.getIntVariable("scrollTop"); | |||
DOM.setElementPropertyInt(getWidget().getElement(), "scrollTop", | |||
getWidget().scrollTop); | |||
getWidget().scrollLeft = uidl.getIntVariable("scrollLeft"); | |||
DOM.setElementPropertyInt(getWidget().getElement(), "scrollLeft", | |||
getWidget().scrollLeft); | |||
} else { | |||
getWidget().scrollable = false; | |||
} | |||
if (uidl.hasAttribute("scrollTo")) { | |||
final ComponentConnector connector = (ComponentConnector) uidl | |||
.getPaintableAttribute("scrollTo", getConnection()); |
@@ -39,6 +39,7 @@ import com.vaadin.server.VaadinServlet; | |||
import com.vaadin.server.VaadinSession; | |||
import com.vaadin.shared.EventId; | |||
import com.vaadin.shared.MouseEventDetails; | |||
import com.vaadin.shared.ui.ui.ScrollClientRpc; | |||
import com.vaadin.shared.ui.ui.UIConstants; | |||
import com.vaadin.shared.ui.ui.UIServerRpc; | |||
import com.vaadin.shared.ui.ui.UIState; | |||
@@ -114,6 +115,16 @@ public abstract class UI extends AbstractSingleComponentContainer implements | |||
private Page page = new Page(this); | |||
/** | |||
* Scroll Y position. | |||
*/ | |||
private int scrollTop = 0; | |||
/** | |||
* Scroll X position | |||
*/ | |||
private int scrollLeft = 0; | |||
private UIServerRpc rpc = new UIServerRpc() { | |||
@Override | |||
public void click(MouseEventDetails mouseDetails) { | |||
@@ -126,6 +137,12 @@ public abstract class UI extends AbstractSingleComponentContainer implements | |||
// TODO We're not doing anything with the view dimensions | |||
getPage().updateBrowserWindowSize(windowWidth, windowHeight); | |||
} | |||
@Override | |||
public void scroll(int scrollTop, int scrollLeft) { | |||
UI.this.scrollTop = scrollTop; | |||
UI.this.scrollLeft = scrollLeft; | |||
} | |||
}; | |||
/** | |||
@@ -560,8 +577,44 @@ public abstract class UI extends AbstractSingleComponentContainer implements | |||
return CurrentInstance.get(UI.class); | |||
} | |||
/** | |||
* Set top offset to which the UI should scroll to. | |||
* | |||
* @param scrollTop | |||
*/ | |||
public void setScrollTop(int scrollTop) { | |||
throw new RuntimeException("Not yet implemented"); | |||
if (scrollTop < 0) { | |||
throw new IllegalArgumentException( | |||
"Scroll offset must be at least 0"); | |||
} | |||
if (this.scrollTop != scrollTop) { | |||
this.scrollTop = scrollTop; | |||
getRpcProxy(ScrollClientRpc.class).setScrollTop(scrollTop); | |||
} | |||
} | |||
public int getScrollTop() { | |||
return scrollTop; | |||
} | |||
/** | |||
* Set left offset to which the UI should scroll to. | |||
* | |||
* @param scrollLeft | |||
*/ | |||
public void setScrollLeft(int scrollLeft) { | |||
if (scrollLeft < 0) { | |||
throw new IllegalArgumentException( | |||
"Scroll offset must be at least 0"); | |||
} | |||
if (this.scrollLeft != scrollLeft) { | |||
this.scrollLeft = scrollLeft; | |||
getRpcProxy(ScrollClientRpc.class).setScrollLeft(scrollLeft); | |||
} | |||
} | |||
public int getScrollLeft() { | |||
return scrollLeft; | |||
} | |||
@Override |
@@ -0,0 +1,26 @@ | |||
/* | |||
* Copyright 2011 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.ui; | |||
import com.vaadin.shared.communication.ClientRpc; | |||
public interface ScrollClientRpc extends ClientRpc { | |||
public void setScrollTop(int scrollTop); | |||
public void setScrollLeft(int scrollLeft); | |||
} |
@@ -23,4 +23,7 @@ public interface UIServerRpc extends ClickRpc, ServerRpc { | |||
@Delayed(lastOnly = true) | |||
public void resize(int viewWidth, int viewHeight, int windowWidth, | |||
int windowHeight); | |||
@Delayed(lastOnly = true) | |||
public void scroll(int scrollTop, int scrollLeft); | |||
} |
@@ -0,0 +1,57 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | |||
<link rel="selenium.base" href="" /> | |||
<title>UIScrollTest</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<thead> | |||
<tr><td rowspan="1" colspan="3">UIScrollTest</td></tr> | |||
</thead><tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/run/com.vaadin.tests.components.uitest.UIScrollTest?restartApplication</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>vaadin=runcomvaadintestscomponentsuitestUIScrollTest::/VVerticalLayout[0]/VOrderedLayout$Slot[1]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VButton[0]/domChild[0]/domChild[0]</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>screenCapture</td> | |||
<td></td> | |||
<td>Halfway_down_button</td> | |||
</tr> | |||
<tr> | |||
<td>scroll</td> | |||
<td>vaadin=runcomvaadintestscomponentsuitestUIScrollTest::</td> | |||
<td>1020</td> | |||
</tr> | |||
<tr> | |||
<td>pause</td> | |||
<td>300</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>vaadin=runcomvaadintestscomponentsuitestUIScrollTest::/VVerticalLayout[0]/VOrderedLayout$Slot[1]/VVerticalLayout[0]/VOrderedLayout$Slot[1]/VButton[0]/domChild[0]/domChild[0]</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertText</td> | |||
<td>//div[@id='runcomvaadintestscomponentsuitestUIScrollTest-1797389287-overlays']/div</td> | |||
<td>Scrolled to 1020 px</td> | |||
</tr> | |||
<tr> | |||
<td>closeNotification</td> | |||
<td>//div[@id='runcomvaadintestscomponentsuitestUIScrollTest-1797389287-overlays']/div</td> | |||
<td>0,0</td> | |||
</tr> | |||
</tbody></table> | |||
</body> | |||
</html> |
@@ -0,0 +1,44 @@ | |||
package com.vaadin.tests.components.uitest; | |||
import com.vaadin.tests.components.TestBase; | |||
import com.vaadin.ui.Button; | |||
import com.vaadin.ui.Button.ClickEvent; | |||
import com.vaadin.ui.Notification; | |||
import com.vaadin.ui.UI; | |||
public class UIScrollTest extends TestBase { | |||
@Override | |||
protected void setup() { | |||
// Set layout to high enough to get scroll. | |||
getLayout().setHeight("2250px"); | |||
addComponent(new Button("scoll to 1000px", new Button.ClickListener() { | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
UI.getCurrent().setScrollTop(1000); | |||
} | |||
})); | |||
addComponent(new Button( | |||
"This button is halfway down. Click to report scroll position.", | |||
new Button.ClickListener() { | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
Notification.show("Scrolled to " | |||
+ event.getButton().getUI().getScrollTop() | |||
+ " px"); | |||
} | |||
})); | |||
} | |||
@Override | |||
protected String getDescription() { | |||
return "Windows can be programmatically scrolled"; | |||
} | |||
@Override | |||
protected Integer getTicketNumber() { | |||
return 9952; | |||
} | |||
} |