Change-Id: Icc4cfc64c0d0bf9993b138eec15a8a73cb0be2f0tags/8.0.0.alpha3
@@ -0,0 +1,685 @@ | |||
/* | |||
* 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.v7.client.ui; | |||
import com.google.gwt.core.client.Scheduler; | |||
import com.google.gwt.core.client.Scheduler.ScheduledCommand; | |||
import com.google.gwt.dom.client.Element; | |||
import com.google.gwt.dom.client.Style.Display; | |||
import com.google.gwt.dom.client.Style.Overflow; | |||
import com.google.gwt.dom.client.Style.Unit; | |||
import com.google.gwt.event.dom.client.KeyCodes; | |||
import com.google.gwt.event.logical.shared.ValueChangeEvent; | |||
import com.google.gwt.event.logical.shared.ValueChangeHandler; | |||
import com.google.gwt.event.shared.HandlerRegistration; | |||
import com.google.gwt.user.client.Command; | |||
import com.google.gwt.user.client.DOM; | |||
import com.google.gwt.user.client.Event; | |||
import com.google.gwt.user.client.Window; | |||
import com.google.gwt.user.client.ui.HTML; | |||
import com.google.gwt.user.client.ui.HasValue; | |||
import com.vaadin.client.ApplicationConnection; | |||
import com.vaadin.client.BrowserInfo; | |||
import com.vaadin.client.WidgetUtil; | |||
import com.vaadin.client.ui.Field; | |||
import com.vaadin.client.ui.SimpleFocusablePanel; | |||
import com.vaadin.client.ui.SubPartAware; | |||
import com.vaadin.client.ui.VLazyExecutor; | |||
import com.vaadin.client.ui.VOverlay; | |||
import com.vaadin.v7.shared.ui.slider.SliderOrientation; | |||
public class VSlider extends SimpleFocusablePanel | |||
implements Field, HasValue<Double>, SubPartAware { | |||
public static final String CLASSNAME = "v-slider"; | |||
/** | |||
* Minimum size (width or height, depending on orientation) of the slider | |||
* base. | |||
*/ | |||
private static final int MIN_SIZE = 50; | |||
protected ApplicationConnection client; | |||
protected String id; | |||
protected boolean immediate; | |||
protected boolean disabled; | |||
protected boolean readonly; | |||
private int acceleration = 1; | |||
protected double min; | |||
protected double max; | |||
protected int resolution; | |||
protected Double value; | |||
protected SliderOrientation orientation = SliderOrientation.HORIZONTAL; | |||
private final HTML feedback = new HTML("", false); | |||
private final VOverlay feedbackPopup = new VOverlay(true, false) { | |||
{ | |||
setOwner(VSlider.this); | |||
} | |||
@Override | |||
public void show() { | |||
super.show(); | |||
updateFeedbackPosition(); | |||
} | |||
}; | |||
/* DOM element for slider's base */ | |||
private final Element base; | |||
private final int BASE_BORDER_WIDTH = 1; | |||
/* DOM element for slider's handle */ | |||
private final Element handle; | |||
/* DOM element for decrement arrow */ | |||
private final Element smaller; | |||
/* DOM element for increment arrow */ | |||
private final Element bigger; | |||
/* Temporary dragging/animation variables */ | |||
private boolean dragging = false; | |||
private VLazyExecutor delayedValueUpdater = new VLazyExecutor(100, | |||
new ScheduledCommand() { | |||
@Override | |||
public void execute() { | |||
fireValueChanged(); | |||
acceleration = 1; | |||
} | |||
}); | |||
public VSlider() { | |||
super(); | |||
base = DOM.createDiv(); | |||
handle = DOM.createDiv(); | |||
smaller = DOM.createDiv(); | |||
bigger = DOM.createDiv(); | |||
setStyleName(CLASSNAME); | |||
getElement().appendChild(bigger); | |||
getElement().appendChild(smaller); | |||
getElement().appendChild(base); | |||
base.appendChild(handle); | |||
// Hide initially | |||
smaller.getStyle().setDisplay(Display.NONE); | |||
bigger.getStyle().setDisplay(Display.NONE); | |||
sinkEvents(Event.MOUSEEVENTS | Event.ONMOUSEWHEEL | Event.KEYEVENTS | |||
| Event.FOCUSEVENTS | Event.TOUCHEVENTS); | |||
feedbackPopup.setWidget(feedback); | |||
} | |||
@Override | |||
public void setStyleName(String style) { | |||
updateStyleNames(style, false); | |||
} | |||
@Override | |||
public void setStylePrimaryName(String style) { | |||
updateStyleNames(style, true); | |||
} | |||
protected void updateStyleNames(String styleName, | |||
boolean isPrimaryStyleName) { | |||
feedbackPopup.removeStyleName(getStylePrimaryName() + "-feedback"); | |||
removeStyleName(getStylePrimaryName() + "-vertical"); | |||
if (isPrimaryStyleName) { | |||
super.setStylePrimaryName(styleName); | |||
} else { | |||
super.setStyleName(styleName); | |||
} | |||
feedbackPopup.addStyleName(getStylePrimaryName() + "-feedback"); | |||
base.setClassName(getStylePrimaryName() + "-base"); | |||
handle.setClassName(getStylePrimaryName() + "-handle"); | |||
smaller.setClassName(getStylePrimaryName() + "-smaller"); | |||
bigger.setClassName(getStylePrimaryName() + "-bigger"); | |||
if (isVertical()) { | |||
addStyleName(getStylePrimaryName() + "-vertical"); | |||
} | |||
} | |||
public void setFeedbackValue(double value) { | |||
feedback.setText(String.valueOf(value)); | |||
} | |||
private void updateFeedbackPosition() { | |||
if (isVertical()) { | |||
feedbackPopup.setPopupPosition( | |||
handle.getAbsoluteLeft() + handle.getOffsetWidth(), | |||
handle.getAbsoluteTop() + handle.getOffsetHeight() / 2 | |||
- feedbackPopup.getOffsetHeight() / 2); | |||
} else { | |||
feedbackPopup.setPopupPosition( | |||
handle.getAbsoluteLeft() + handle.getOffsetWidth() / 2 | |||
- feedbackPopup.getOffsetWidth() / 2, | |||
handle.getAbsoluteTop() - feedbackPopup.getOffsetHeight()); | |||
} | |||
} | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public void buildBase() { | |||
final String styleAttribute = isVertical() ? "height" : "width"; | |||
final String oppositeStyleAttribute = isVertical() ? "width" : "height"; | |||
final String domProperty = isVertical() ? "offsetHeight" | |||
: "offsetWidth"; | |||
// clear unnecessary opposite style attribute | |||
base.getStyle().clearProperty(oppositeStyleAttribute); | |||
/* | |||
* To resolve defect #13681 we should not return from method buildBase() | |||
* if slider has no parentElement, because such operations as | |||
* buildHandle() and setValues(), which are needed for Slider, are | |||
* called at the end of method buildBase(). And these methods will not | |||
* be called if there is no parentElement. So, instead of returning from | |||
* method buildBase() if there is no parentElement "if condition" is | |||
* applied to call code for parentElement only in case it exists. | |||
*/ | |||
if (getElement().hasParentElement()) { | |||
final Element p = getElement(); | |||
if (p.getPropertyInt(domProperty) > MIN_SIZE) { | |||
if (isVertical()) { | |||
setHeight(); | |||
} else { | |||
base.getStyle().clearProperty(styleAttribute); | |||
} | |||
} else { | |||
// Set minimum size and adjust after all components have | |||
// (supposedly) been drawn completely. | |||
base.getStyle().setPropertyPx(styleAttribute, MIN_SIZE); | |||
Scheduler.get().scheduleDeferred(new Command() { | |||
@Override | |||
public void execute() { | |||
final Element p = getElement(); | |||
if (p.getPropertyInt(domProperty) > MIN_SIZE + 5 | |||
|| propertyNotNullOrEmpty(styleAttribute, p)) { | |||
if (isVertical()) { | |||
setHeight(); | |||
} else { | |||
base.getStyle().clearProperty(styleAttribute); | |||
} | |||
// Ensure correct position | |||
setValue(value, false); | |||
} | |||
} | |||
// Style has non empty property | |||
private boolean propertyNotNullOrEmpty( | |||
final String styleAttribute, final Element p) { | |||
return p.getStyle().getProperty(styleAttribute) != null | |||
&& !p.getStyle().getProperty(styleAttribute) | |||
.isEmpty(); | |||
} | |||
}); | |||
} | |||
} | |||
if (!isVertical()) { | |||
// Draw handle with a delay to allow base to gain maximum width | |||
Scheduler.get().scheduleDeferred(new Command() { | |||
@Override | |||
public void execute() { | |||
buildHandle(); | |||
setValue(value, false); | |||
} | |||
}); | |||
} else { | |||
buildHandle(); | |||
setValue(value, false); | |||
} | |||
// TODO attach listeners for focusing and arrow keys | |||
} | |||
void buildHandle() { | |||
final String handleAttribute = isVertical() ? "marginTop" | |||
: "marginLeft"; | |||
final String oppositeHandleAttribute = isVertical() ? "marginLeft" | |||
: "marginTop"; | |||
handle.getStyle().setProperty(handleAttribute, "0"); | |||
// clear unnecessary opposite handle attribute | |||
handle.getStyle().clearProperty(oppositeHandleAttribute); | |||
} | |||
@Override | |||
public void onBrowserEvent(Event event) { | |||
if (disabled || readonly) { | |||
return; | |||
} | |||
final Element targ = DOM.eventGetTarget(event); | |||
if (DOM.eventGetType(event) == Event.ONMOUSEWHEEL) { | |||
processMouseWheelEvent(event); | |||
} else if (dragging || targ == handle) { | |||
processHandleEvent(event); | |||
} else if (targ == smaller) { | |||
decreaseValue(true); | |||
} else if (targ == bigger) { | |||
increaseValue(true); | |||
} else if (DOM.eventGetType(event) == Event.MOUSEEVENTS) { | |||
processBaseEvent(event); | |||
} else if (BrowserInfo.get().isGecko() | |||
&& DOM.eventGetType(event) == Event.ONKEYPRESS | |||
|| !BrowserInfo.get().isGecko() | |||
&& DOM.eventGetType(event) == Event.ONKEYDOWN) { | |||
if (handleNavigation(event.getKeyCode(), event.getCtrlKey(), | |||
event.getShiftKey())) { | |||
feedbackPopup.show(); | |||
delayedValueUpdater.trigger(); | |||
DOM.eventPreventDefault(event); | |||
DOM.eventCancelBubble(event, true); | |||
} | |||
} else if (targ.equals(getElement()) | |||
&& DOM.eventGetType(event) == Event.ONFOCUS) { | |||
feedbackPopup.show(); | |||
} else if (targ.equals(getElement()) | |||
&& DOM.eventGetType(event) == Event.ONBLUR) { | |||
feedbackPopup.hide(); | |||
} else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) { | |||
feedbackPopup.show(); | |||
} | |||
if (WidgetUtil.isTouchEvent(event)) { | |||
event.preventDefault(); // avoid simulated events | |||
event.stopPropagation(); | |||
} | |||
} | |||
private void processMouseWheelEvent(final Event event) { | |||
final int dir = DOM.eventGetMouseWheelVelocityY(event); | |||
if (dir < 0) { | |||
increaseValue(false); | |||
} else { | |||
decreaseValue(false); | |||
} | |||
delayedValueUpdater.trigger(); | |||
DOM.eventPreventDefault(event); | |||
DOM.eventCancelBubble(event, true); | |||
} | |||
private void processHandleEvent(Event event) { | |||
switch (DOM.eventGetType(event)) { | |||
case Event.ONMOUSEDOWN: | |||
case Event.ONTOUCHSTART: | |||
if (!disabled && !readonly) { | |||
focus(); | |||
feedbackPopup.show(); | |||
dragging = true; | |||
handle.setClassName(getStylePrimaryName() + "-handle"); | |||
handle.addClassName(getStylePrimaryName() + "-handle-active"); | |||
DOM.setCapture(getElement()); | |||
DOM.eventPreventDefault(event); // prevent selecting text | |||
DOM.eventCancelBubble(event, true); | |||
event.stopPropagation(); | |||
} | |||
break; | |||
case Event.ONMOUSEMOVE: | |||
case Event.ONTOUCHMOVE: | |||
if (dragging) { | |||
setValueByEvent(event, false); | |||
updateFeedbackPosition(); | |||
event.stopPropagation(); | |||
} | |||
break; | |||
case Event.ONTOUCHEND: | |||
feedbackPopup.hide(); | |||
case Event.ONMOUSEUP: | |||
// feedbackPopup.hide(); | |||
dragging = false; | |||
handle.setClassName(getStylePrimaryName() + "-handle"); | |||
DOM.releaseCapture(getElement()); | |||
setValueByEvent(event, true); | |||
event.stopPropagation(); | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
private void processBaseEvent(Event event) { | |||
if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) { | |||
if (!disabled && !readonly && !dragging) { | |||
setValueByEvent(event, true); | |||
DOM.eventCancelBubble(event, true); | |||
} | |||
} | |||
} | |||
private void decreaseValue(boolean updateToServer) { | |||
setValue(new Double(value.doubleValue() - Math.pow(10, -resolution)), | |||
updateToServer); | |||
} | |||
private void increaseValue(boolean updateToServer) { | |||
setValue(new Double(value.doubleValue() + Math.pow(10, -resolution)), | |||
updateToServer); | |||
} | |||
private void setValueByEvent(Event event, boolean updateToServer) { | |||
double v = min; // Fallback to min | |||
final int coord = getEventPosition(event); | |||
final int handleSize, baseSize, baseOffset; | |||
if (isVertical()) { | |||
handleSize = handle.getOffsetHeight(); | |||
baseSize = base.getOffsetHeight(); | |||
baseOffset = base.getAbsoluteTop() - Window.getScrollTop() | |||
- handleSize / 2; | |||
} else { | |||
handleSize = handle.getOffsetWidth(); | |||
baseSize = base.getOffsetWidth(); | |||
baseOffset = base.getAbsoluteLeft() - Window.getScrollLeft() | |||
+ handleSize / 2; | |||
} | |||
if (isVertical()) { | |||
v = (baseSize - (coord - baseOffset)) | |||
/ (double) (baseSize - handleSize) * (max - min) + min; | |||
} else { | |||
v = (coord - baseOffset) / (double) (baseSize - handleSize) | |||
* (max - min) + min; | |||
} | |||
if (v < min) { | |||
v = min; | |||
} else if (v > max) { | |||
v = max; | |||
} | |||
setValue(v, updateToServer); | |||
} | |||
/** | |||
* TODO consider extracting touches support to an impl class specific for | |||
* webkit (only browser that really supports touches). | |||
* | |||
* @param event | |||
* @return | |||
*/ | |||
protected int getEventPosition(Event event) { | |||
if (isVertical()) { | |||
return WidgetUtil.getTouchOrMouseClientY(event); | |||
} else { | |||
return WidgetUtil.getTouchOrMouseClientX(event); | |||
} | |||
} | |||
public void iLayout() { | |||
if (isVertical()) { | |||
setHeight(); | |||
} | |||
// Update handle position | |||
setValue(value, false); | |||
} | |||
private void setHeight() { | |||
// Calculate decoration size | |||
base.getStyle().setHeight(0, Unit.PX); | |||
base.getStyle().setOverflow(Overflow.HIDDEN); | |||
int h = getElement().getOffsetHeight(); | |||
if (h < MIN_SIZE) { | |||
h = MIN_SIZE; | |||
} | |||
base.getStyle().setHeight(h, Unit.PX); | |||
base.getStyle().clearOverflow(); | |||
} | |||
private void fireValueChanged() { | |||
ValueChangeEvent.fire(VSlider.this, value); | |||
} | |||
/** | |||
* Handles the keyboard events handled by the Slider | |||
* | |||
* @param event | |||
* The keyboard event received | |||
* @return true iff the navigation event was handled | |||
*/ | |||
public boolean handleNavigation(int keycode, boolean ctrl, boolean shift) { | |||
// No support for ctrl moving | |||
if (ctrl) { | |||
return false; | |||
} | |||
if (keycode == getNavigationUpKey() && isVertical() | |||
|| keycode == getNavigationRightKey() && !isVertical()) { | |||
if (shift) { | |||
for (int a = 0; a < acceleration; a++) { | |||
increaseValue(false); | |||
} | |||
acceleration++; | |||
} else { | |||
increaseValue(false); | |||
} | |||
return true; | |||
} else if (keycode == getNavigationDownKey() && isVertical() | |||
|| keycode == getNavigationLeftKey() && !isVertical()) { | |||
if (shift) { | |||
for (int a = 0; a < acceleration; a++) { | |||
decreaseValue(false); | |||
} | |||
acceleration++; | |||
} else { | |||
decreaseValue(false); | |||
} | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Get the key that increases the vertical slider. By default it is the up | |||
* arrow key but by overriding this you can change the key to whatever you | |||
* want. | |||
* | |||
* @return The keycode of the key | |||
*/ | |||
protected int getNavigationUpKey() { | |||
return KeyCodes.KEY_UP; | |||
} | |||
/** | |||
* Get the key that decreases the vertical slider. By default it is the down | |||
* arrow key but by overriding this you can change the key to whatever you | |||
* want. | |||
* | |||
* @return The keycode of the key | |||
*/ | |||
protected int getNavigationDownKey() { | |||
return KeyCodes.KEY_DOWN; | |||
} | |||
/** | |||
* Get the key that decreases the horizontal slider. By default it is the | |||
* left arrow key but by overriding this you can change the key to whatever | |||
* you want. | |||
* | |||
* @return The keycode of the key | |||
*/ | |||
protected int getNavigationLeftKey() { | |||
return KeyCodes.KEY_LEFT; | |||
} | |||
/** | |||
* Get the key that increases the horizontal slider. By default it is the | |||
* right arrow key but by overriding this you can change the key to whatever | |||
* you want. | |||
* | |||
* @return The keycode of the key | |||
*/ | |||
protected int getNavigationRightKey() { | |||
return KeyCodes.KEY_RIGHT; | |||
} | |||
public void setConnection(ApplicationConnection client) { | |||
this.client = client; | |||
} | |||
public void setId(String id) { | |||
this.id = id; | |||
} | |||
public void setImmediate(boolean immediate) { | |||
this.immediate = immediate; | |||
} | |||
public void setDisabled(boolean disabled) { | |||
this.disabled = disabled; | |||
} | |||
public void setReadOnly(boolean readonly) { | |||
this.readonly = readonly; | |||
} | |||
private boolean isVertical() { | |||
return orientation == SliderOrientation.VERTICAL; | |||
} | |||
public void setOrientation(SliderOrientation orientation) { | |||
if (this.orientation != orientation) { | |||
this.orientation = orientation; | |||
updateStyleNames(getStylePrimaryName(), true); | |||
} | |||
} | |||
public void setMinValue(double value) { | |||
min = value; | |||
} | |||
public void setMaxValue(double value) { | |||
max = value; | |||
} | |||
public void setResolution(int resolution) { | |||
this.resolution = resolution; | |||
} | |||
@Override | |||
public HandlerRegistration addValueChangeHandler( | |||
ValueChangeHandler<Double> handler) { | |||
return addHandler(handler, ValueChangeEvent.getType()); | |||
} | |||
@Override | |||
public Double getValue() { | |||
return value; | |||
} | |||
@Override | |||
public void setValue(Double value) { | |||
if (value < min) { | |||
value = min; | |||
} else if (value > max) { | |||
value = max; | |||
} | |||
// Update handle position | |||
final String styleAttribute = isVertical() ? "marginTop" : "marginLeft"; | |||
final String domProperty = isVertical() ? "offsetHeight" | |||
: "offsetWidth"; | |||
final int handleSize = handle.getPropertyInt(domProperty); | |||
final int baseSize = base.getPropertyInt(domProperty) | |||
- 2 * BASE_BORDER_WIDTH; | |||
final int range = baseSize - handleSize; | |||
double v = value.doubleValue(); | |||
// Round value to resolution | |||
if (resolution > 0) { | |||
v = Math.round(v * Math.pow(10, resolution)); | |||
v = v / Math.pow(10, resolution); | |||
} else { | |||
v = Math.round(v); | |||
} | |||
final double valueRange = max - min; | |||
double p = 0; | |||
if (valueRange > 0) { | |||
p = range * ((v - min) / valueRange); | |||
} | |||
if (p < 0) { | |||
p = 0; | |||
} | |||
if (isVertical()) { | |||
p = range - p; | |||
} | |||
final double pos = p; | |||
handle.getStyle().setPropertyPx(styleAttribute, (int) Math.round(pos)); | |||
// Update value | |||
this.value = new Double(v); | |||
setFeedbackValue(v); | |||
} | |||
@Override | |||
public void setValue(Double value, boolean fireEvents) { | |||
if (value == null) { | |||
return; | |||
} | |||
setValue(value); | |||
if (fireEvents) { | |||
fireValueChanged(); | |||
} | |||
} | |||
@Override | |||
public com.google.gwt.user.client.Element getSubPartElement( | |||
String subPart) { | |||
if (subPart.equals("popup")) { | |||
feedbackPopup.show(); | |||
return feedbackPopup.getElement(); | |||
} | |||
return null; | |||
} | |||
@Override | |||
public String getSubPartName( | |||
com.google.gwt.user.client.Element subElement) { | |||
if (feedbackPopup.getElement().isOrHasChild(subElement)) { | |||
return "popup"; | |||
} | |||
return null; | |||
} | |||
} |
@@ -0,0 +1,96 @@ | |||
/* | |||
* 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.v7.client.ui.slider; | |||
import com.google.gwt.event.logical.shared.ValueChangeEvent; | |||
import com.google.gwt.event.logical.shared.ValueChangeHandler; | |||
import com.vaadin.client.communication.RpcProxy; | |||
import com.vaadin.client.communication.StateChangeEvent; | |||
import com.vaadin.client.ui.layout.ElementResizeEvent; | |||
import com.vaadin.client.ui.layout.ElementResizeListener; | |||
import com.vaadin.shared.ui.Connect; | |||
import com.vaadin.v7.client.ui.AbstractFieldConnector; | |||
import com.vaadin.v7.client.ui.VSlider; | |||
import com.vaadin.v7.shared.ui.slider.SliderServerRpc; | |||
import com.vaadin.v7.shared.ui.slider.SliderState; | |||
@Connect(com.vaadin.v7.ui.Slider.class) | |||
public class SliderConnector extends AbstractFieldConnector | |||
implements ValueChangeHandler<Double> { | |||
protected SliderServerRpc rpc = RpcProxy.create(SliderServerRpc.class, | |||
this); | |||
private final ElementResizeListener resizeListener = new ElementResizeListener() { | |||
@Override | |||
public void onElementResize(ElementResizeEvent e) { | |||
getWidget().iLayout(); | |||
} | |||
}; | |||
@Override | |||
public void init() { | |||
super.init(); | |||
getWidget().setConnection(getConnection()); | |||
getWidget().addValueChangeHandler(this); | |||
getLayoutManager().addElementResizeListener(getWidget().getElement(), | |||
resizeListener); | |||
} | |||
@Override | |||
public void onUnregister() { | |||
super.onUnregister(); | |||
getLayoutManager().removeElementResizeListener(getWidget().getElement(), | |||
resizeListener); | |||
} | |||
@Override | |||
public VSlider getWidget() { | |||
return (VSlider) super.getWidget(); | |||
} | |||
@Override | |||
public SliderState getState() { | |||
return (SliderState) super.getState(); | |||
} | |||
@Override | |||
public void onValueChange(ValueChangeEvent<Double> event) { | |||
getState().value = event.getValue(); | |||
rpc.valueChanged(event.getValue()); | |||
} | |||
@Override | |||
public void onStateChanged(StateChangeEvent stateChangeEvent) { | |||
super.onStateChanged(stateChangeEvent); | |||
getWidget().setId(getConnectorId()); | |||
getWidget().setImmediate(getState().immediate); | |||
getWidget().setDisabled(!isEnabled()); | |||
getWidget().setReadOnly(isReadOnly()); | |||
getWidget().setOrientation(getState().orientation); | |||
getWidget().setMinValue(getState().minValue); | |||
getWidget().setMaxValue(getState().maxValue); | |||
getWidget().setResolution(getState().resolution); | |||
getWidget().setValue(getState().value, false); | |||
getWidget().buildBase(); | |||
getWidget().setTabIndex(getState().tabIndex); | |||
} | |||
} |
@@ -0,0 +1,399 @@ | |||
/* | |||
* 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.v7.ui; | |||
import java.util.Collection; | |||
import org.jsoup.nodes.Attributes; | |||
import org.jsoup.nodes.Element; | |||
import com.vaadin.ui.declarative.DesignAttributeHandler; | |||
import com.vaadin.ui.declarative.DesignContext; | |||
import com.vaadin.v7.shared.ui.slider.SliderOrientation; | |||
import com.vaadin.v7.shared.ui.slider.SliderServerRpc; | |||
import com.vaadin.v7.shared.ui.slider.SliderState;; | |||
/** | |||
* A component for selecting a numerical value within a range. | |||
* | |||
* @author Vaadin Ltd. | |||
*/ | |||
@Deprecated | |||
public class Slider extends AbstractField<Double> { | |||
private SliderServerRpc rpc = new SliderServerRpc() { | |||
@Override | |||
public void valueChanged(double value) { | |||
/* | |||
* Client side updates the state before sending the event so we need | |||
* to make sure the cached state is updated to match the client. If | |||
* we do not do this, a reverting setValue() call in a listener will | |||
* not cause the new state to be sent to the client. | |||
* | |||
* See #12133. | |||
*/ | |||
getUI().getConnectorTracker().getDiffState(Slider.this).put("value", | |||
value); | |||
try { | |||
setValue(value, true); | |||
} catch (final ValueOutOfBoundsException e) { | |||
// Convert to nearest bound | |||
double out = e.getValue().doubleValue(); | |||
if (out < getState().minValue) { | |||
out = getState().minValue; | |||
} | |||
if (out > getState().maxValue) { | |||
out = getState().maxValue; | |||
} | |||
Slider.super.setValue(new Double(out), false); | |||
} | |||
} | |||
}; | |||
/** | |||
* Default slider constructor. Sets all values to defaults and the slide | |||
* handle at minimum value. | |||
* | |||
*/ | |||
public Slider() { | |||
super(); | |||
registerRpc(rpc); | |||
super.setValue(new Double(getState().minValue)); | |||
} | |||
/** | |||
* Create a new slider with the caption given as parameter. | |||
* | |||
* The range of the slider is set to 0-100 and only integer values are | |||
* allowed. | |||
* | |||
* @param caption | |||
* The caption for this slider (e.g. "Volume"). | |||
*/ | |||
public Slider(String caption) { | |||
this(); | |||
setCaption(caption); | |||
} | |||
/** | |||
* Create a new slider with the given range and resolution. | |||
* | |||
* @param min | |||
* The minimum value of the slider | |||
* @param max | |||
* The maximum value of the slider | |||
* @param resolution | |||
* The number of digits after the decimal point. | |||
*/ | |||
public Slider(double min, double max, int resolution) { | |||
this(); | |||
setResolution(resolution); | |||
setMax(max); | |||
setMin(min); | |||
} | |||
/** | |||
* Create a new slider with the given range that only allows integer values. | |||
* | |||
* @param min | |||
* The minimum value of the slider | |||
* @param max | |||
* The maximum value of the slider | |||
*/ | |||
public Slider(int min, int max) { | |||
this(); | |||
setMin(min); | |||
setMax(max); | |||
setResolution(0); | |||
} | |||
/** | |||
* Create a new slider with the given caption and range that only allows | |||
* integer values. | |||
* | |||
* @param caption | |||
* The caption for the slider | |||
* @param min | |||
* The minimum value of the slider | |||
* @param max | |||
* The maximum value of the slider | |||
*/ | |||
public Slider(String caption, int min, int max) { | |||
this(min, max); | |||
setCaption(caption); | |||
} | |||
@Override | |||
public SliderState getState() { | |||
return (SliderState) super.getState(); | |||
} | |||
@Override | |||
public SliderState getState(boolean markAsDirty) { | |||
return (SliderState) super.getState(markAsDirty); | |||
} | |||
/** | |||
* Gets the maximum slider value | |||
* | |||
* @return the largest value the slider can have | |||
*/ | |||
public double getMax() { | |||
return getState(false).maxValue; | |||
} | |||
/** | |||
* Set the maximum slider value. If the current value of the slider is | |||
* larger than this, the value is set to the new maximum. | |||
* | |||
* @param max | |||
* The new maximum slider value | |||
*/ | |||
public void setMax(double max) { | |||
double roundedMax = getRoundedValue(max); | |||
getState().maxValue = roundedMax; | |||
if (getMin() > roundedMax) { | |||
getState().minValue = roundedMax; | |||
} | |||
if (getValue() > roundedMax) { | |||
setValue(roundedMax); | |||
} | |||
} | |||
/** | |||
* Gets the minimum slider value | |||
* | |||
* @return the smallest value the slider can have | |||
*/ | |||
public double getMin() { | |||
return getState(false).minValue; | |||
} | |||
/** | |||
* Set the minimum slider value. If the current value of the slider is | |||
* smaller than this, the value is set to the new minimum. | |||
* | |||
* @param min | |||
* The new minimum slider value | |||
*/ | |||
public void setMin(double min) { | |||
double roundedMin = getRoundedValue(min); | |||
getState().minValue = roundedMin; | |||
if (getMax() < roundedMin) { | |||
getState().maxValue = roundedMin; | |||
} | |||
if (getValue() < roundedMin) { | |||
setValue(roundedMin); | |||
} | |||
} | |||
/** | |||
* Get the current orientation of the slider (horizontal or vertical). | |||
* | |||
* @return {@link SliderOrientation#HORIZONTAL} or | |||
* {@link SliderOrientation#VERTICAL} | |||
*/ | |||
public SliderOrientation getOrientation() { | |||
return getState(false).orientation; | |||
} | |||
/** | |||
* Set the orientation of the slider. | |||
* | |||
* @param orientation | |||
* The new orientation, either | |||
* {@link SliderOrientation#HORIZONTAL} or | |||
* {@link SliderOrientation#VERTICAL} | |||
*/ | |||
public void setOrientation(SliderOrientation orientation) { | |||
getState().orientation = orientation; | |||
} | |||
/** | |||
* Get the current resolution of the slider. The resolution is the number of | |||
* digits after the decimal point. | |||
* | |||
* @return resolution | |||
*/ | |||
public int getResolution() { | |||
return getState(false).resolution; | |||
} | |||
/** | |||
* Set a new resolution for the slider. The resolution is the number of | |||
* digits after the decimal point. | |||
* | |||
* @throws IllegalArgumentException | |||
* if resolution is negative. | |||
* | |||
* @param resolution | |||
*/ | |||
public void setResolution(int resolution) { | |||
if (resolution < 0) { | |||
throw new IllegalArgumentException( | |||
"Cannot set a negative resolution to Slider"); | |||
} | |||
getState().resolution = resolution; | |||
} | |||
/** | |||
* Sets the value of the slider. | |||
* | |||
* @param value | |||
* The new value of the slider. | |||
* @param repaintIsNotNeeded | |||
* If true, client-side is not requested to repaint itself. | |||
* @throws ValueOutOfBoundsException | |||
* If the given value is not inside the range of the slider. | |||
* @see #setMin(double) {@link #setMax(double)} | |||
*/ | |||
@Override | |||
protected void setValue(Double value, boolean repaintIsNotNeeded) { | |||
double newValue = getRoundedValue(value); | |||
if (getMin() > newValue || getMax() < newValue) { | |||
throw new ValueOutOfBoundsException(newValue); | |||
} | |||
getState().value = newValue; | |||
super.setValue(newValue, repaintIsNotNeeded); | |||
} | |||
private double getRoundedValue(Double value) { | |||
final double v = value.doubleValue(); | |||
final int resolution = getResolution(); | |||
double ratio = Math.pow(10, resolution); | |||
if (v >= 0) { | |||
return Math.floor(v * ratio) / ratio; | |||
} else { | |||
return Math.ceil(v * ratio) / ratio; | |||
} | |||
} | |||
@Override | |||
public void setValue(Double newFieldValue) { | |||
super.setValue(newFieldValue); | |||
getState().value = newFieldValue; | |||
} | |||
/* | |||
* Overridden to keep the shared state in sync with the AbstractField | |||
* internal value. Should be removed once AbstractField is refactored to use | |||
* shared state. | |||
* | |||
* See tickets #10921 and #11064. | |||
*/ | |||
@Override | |||
protected void setInternalValue(Double newValue) { | |||
super.setInternalValue(newValue); | |||
if (newValue == null) { | |||
newValue = 0.0; | |||
} | |||
getState().value = newValue; | |||
} | |||
/** | |||
* Thrown when the value of the slider is about to be set to a value that is | |||
* outside the valid range of the slider. | |||
* | |||
* @author Vaadin Ltd. | |||
* | |||
*/ | |||
public class ValueOutOfBoundsException extends RuntimeException { | |||
private final Double value; | |||
/** | |||
* Constructs an <code>ValueOutOfBoundsException</code> with the | |||
* specified detail message. | |||
* | |||
* @param valueOutOfBounds | |||
*/ | |||
public ValueOutOfBoundsException(Double valueOutOfBounds) { | |||
super(String.format("Value %s is out of bounds: [%s, %s]", | |||
valueOutOfBounds, getMin(), getMax())); | |||
value = valueOutOfBounds; | |||
} | |||
/** | |||
* Gets the value that is outside the valid range of the slider. | |||
* | |||
* @return the value that is out of bounds | |||
*/ | |||
public Double getValue() { | |||
return value; | |||
} | |||
} | |||
@Override | |||
public Class<Double> getType() { | |||
return Double.class; | |||
} | |||
@Override | |||
public void clear() { | |||
super.setValue(Double.valueOf(getState().minValue)); | |||
} | |||
@Override | |||
public boolean isEmpty() { | |||
// Slider is never really "empty" | |||
return false; | |||
} | |||
@Override | |||
public void readDesign(Element design, DesignContext context) { | |||
super.readDesign(design, context); | |||
Attributes attr = design.attributes(); | |||
if (attr.hasKey("vertical")) { | |||
setOrientation(SliderOrientation.VERTICAL); | |||
} | |||
if (attr.hasKey("value")) { | |||
Double newFieldValue = DesignAttributeHandler.readAttribute("value", | |||
attr, Double.class); | |||
setValue(newFieldValue, false, true); | |||
} | |||
} | |||
@Override | |||
public void writeDesign(Element design, DesignContext context) { | |||
super.writeDesign(design, context); | |||
if (getOrientation() == SliderOrientation.VERTICAL) { | |||
design.attr("vertical", true); | |||
} | |||
Slider defaultSlider = context.getDefaultInstance(this); | |||
DesignAttributeHandler.writeAttribute(this, "value", | |||
design.attributes(), defaultSlider); | |||
} | |||
@Override | |||
protected Collection<String> getCustomAttributes() { | |||
Collection<String> result = super.getCustomAttributes(); | |||
result.add("orientation"); | |||
result.add("vertical"); | |||
return result; | |||
} | |||
} |
@@ -0,0 +1,81 @@ | |||
/* | |||
* 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.server.component.slider; | |||
import org.junit.Test; | |||
import com.vaadin.shared.ui.slider.SliderOrientation; | |||
import com.vaadin.tests.design.DeclarativeTestBase; | |||
import com.vaadin.ui.Slider; | |||
/** | |||
* Tests declarative support for implementations of {@link Slider}. | |||
* | |||
* @since | |||
* @author Vaadin Ltd | |||
*/ | |||
public class SliderDeclarativeTest extends DeclarativeTestBase<Slider> { | |||
@Test | |||
public void testDefault() { | |||
String design = "<vaadin-slider>"; | |||
Slider expected = new Slider(); | |||
testRead(design, expected); | |||
testWrite(design, expected); | |||
} | |||
@Test | |||
public void testHorizontal() { | |||
String design = "<vaadin-slider min=10 max=20 resolution=1 value=12.3>"; | |||
Slider expected = new Slider(); | |||
expected.setMin(10.0); | |||
expected.setMax(20.0); | |||
expected.setResolution(1); | |||
expected.setValue(12.3); | |||
testRead(design, expected); | |||
testWrite(design, expected); | |||
} | |||
@Test | |||
public void testVertical() { | |||
String design = "<vaadin-slider vertical>"; | |||
Slider expected = new Slider(); | |||
expected.setOrientation(SliderOrientation.VERTICAL); | |||
testRead(design, expected); | |||
testWrite(design, expected); | |||
} | |||
@Test | |||
public void testReadOnlyValue() { | |||
String design = "<vaadin-slider readonly min=10 max=20 resolution=1 value=12.3>"; | |||
Slider expected = new Slider(); | |||
expected.setMin(10.0); | |||
expected.setMax(20.0); | |||
expected.setResolution(1); | |||
expected.setValue(12.3); | |||
expected.setReadOnly(true); | |||
testRead(design, expected); | |||
testWrite(design, expected); | |||
} | |||
} |
@@ -0,0 +1,135 @@ | |||
package com.vaadin.tests.server.component.slider; | |||
import static org.hamcrest.CoreMatchers.containsString; | |||
import static org.hamcrest.MatcherAssert.assertThat; | |||
import static org.hamcrest.core.Is.is; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
import com.vaadin.ui.Slider; | |||
public class SliderTest { | |||
@Test | |||
public void minCannotBeLargerThanMax() { | |||
Slider slider = new Slider(); | |||
slider.setMax(100); | |||
slider.setMin(101); | |||
assertThat(slider.getMin(), is(101.0)); | |||
assertThat(slider.getMax(), is(101.0)); | |||
} | |||
@Test | |||
public void maxCannotBeSmallerThanMin() { | |||
Slider slider = new Slider(); | |||
slider.setMin(50); | |||
slider.setMax(10); | |||
assertThat(slider.getMax(), is(10.0)); | |||
assertThat(slider.getMin(), is(10.0)); | |||
} | |||
@Test | |||
public void valueOutOfBoundsExceptionMessageContainsBounds() { | |||
Slider slider = new Slider(); | |||
try { | |||
slider.setValue(-1.0); | |||
} catch (Slider.ValueOutOfBoundsException e) { | |||
assertThat(e.getMessage(), | |||
containsString("Value -1.0 is out of bounds: [0.0, 100.0]")); | |||
} | |||
} | |||
@Test | |||
public void valueIsSet() { | |||
Slider slider = new Slider(); | |||
slider.setValue(5.0); | |||
assertThat(slider.getValue(), is(5.0)); | |||
} | |||
@Test | |||
public void valueCannotBeOutOfBounds() { | |||
Slider s = new Slider(0, 10); | |||
try { | |||
s.setValue(20.0); | |||
Assert.fail("Should throw out of bounds exception"); | |||
} catch (Slider.ValueOutOfBoundsException e) { | |||
// TODO: handle exception | |||
} | |||
} | |||
@Test | |||
public void valueCanHaveLargePrecision() { | |||
Slider slider = new Slider(); | |||
slider.setResolution(20); | |||
slider.setValue(99.01234567891234567890123456789); | |||
assertThat(slider.getValue(), is(99.01234567891234567890123456789)); | |||
} | |||
@Test | |||
public void doublesCanBeUsedAsLimits() { | |||
Slider slider = new Slider(1.5, 2.5, 1); | |||
assertThat(slider.getMin(), is(1.5)); | |||
assertThat(slider.getValue(), is(1.5)); | |||
assertThat(slider.getMax(), is(2.5)); | |||
} | |||
@Test | |||
public void valuesGreaterThanIntMaxValueCanBeUsed() { | |||
double minValue = (double) Integer.MAX_VALUE + 1; | |||
Slider s = new Slider(minValue, minValue + 1, 0); | |||
assertThat(s.getValue(), is(minValue)); | |||
} | |||
@Test | |||
public void negativeValuesCanBeUsed() { | |||
Slider slider = new Slider(-0.7, 1.0, 0); | |||
slider.setValue(-0.4); | |||
assertThat(slider.getValue(), is(-0.0)); | |||
} | |||
@Test | |||
public void boundariesAreRounded() { | |||
Slider slider = new Slider(1.5, 2.5, 0); | |||
slider.setValue(1.0); | |||
assertThat(slider.getValue(), is(1.0)); | |||
assertThat(slider.getMin(), is(1.0)); | |||
assertThat(slider.getMax(), is(2.0)); | |||
} | |||
@Test | |||
public void valueWithSmallerPrecisionCanBeUsed() { | |||
Slider slider = new Slider(0, 100, 10); | |||
slider.setValue(1.2); | |||
assertThat(slider.getValue(), is(1.2)); | |||
} | |||
@Test | |||
public void valueWithLargerPrecisionCanBeUsed() { | |||
Slider slider = new Slider(0, 100, 2); | |||
slider.setValue(1.2345); | |||
assertThat(slider.getValue(), is(1.23)); | |||
} | |||
} |
@@ -0,0 +1,20 @@ | |||
/* | |||
* 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.v7.shared.ui.slider; | |||
public enum SliderOrientation { | |||
HORIZONTAL, VERTICAL; | |||
} |
@@ -0,0 +1,29 @@ | |||
/* | |||
* 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.v7.shared.ui.slider; | |||
import com.vaadin.shared.communication.ServerRpc; | |||
public interface SliderServerRpc extends ServerRpc { | |||
/** | |||
* Invoked when the value of a variable has changed. Slider listeners are | |||
* notified if the slider value has changed. | |||
* | |||
* @param value | |||
*/ | |||
public void valueChanged(double value); | |||
} |
@@ -0,0 +1,43 @@ | |||
/* | |||
* 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.v7.shared.ui.slider; | |||
import com.vaadin.shared.annotations.NoLayout; | |||
import com.vaadin.v7.shared.AbstractFieldState; | |||
public class SliderState extends AbstractFieldState { | |||
{ | |||
primaryStyleName = "v-slider"; | |||
} | |||
@NoLayout | |||
public double value; | |||
@NoLayout | |||
public double maxValue = 100; | |||
@NoLayout | |||
public double minValue = 0; | |||
/** | |||
* The number of fractional digits that are considered significant. Must be | |||
* non-negative. | |||
*/ | |||
@NoLayout | |||
public int resolution = 0; | |||
public SliderOrientation orientation = SliderOrientation.HORIZONTAL; | |||
} |
@@ -0,0 +1,43 @@ | |||
/* | |||
* 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.v7.tests.components.slider; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.tests.components.AbstractTestUI; | |||
import com.vaadin.ui.Slider; | |||
public class SliderFeedback extends AbstractTestUI { | |||
@Override | |||
protected void setup(VaadinRequest request) { | |||
Slider slider = new Slider(0, 5); | |||
slider.setWidth(800, Unit.PIXELS); | |||
slider.setMin(0); | |||
slider.setMax(1e12); | |||
addComponent(slider); | |||
} | |||
@Override | |||
protected String getTestDescription() { | |||
return "Slider feedback popup should display the correct value"; | |||
} | |||
@Override | |||
protected Integer getTicketNumber() { | |||
return 18192; | |||
} | |||
} |
@@ -0,0 +1,79 @@ | |||
package com.vaadin.v7.tests.components.slider; | |||
import java.util.LinkedHashMap; | |||
import com.vaadin.tests.components.abstractfield.LegacyAbstractFieldTest; | |||
import com.vaadin.v7.shared.ui.slider.SliderOrientation; | |||
import com.vaadin.v7.ui.Slider; | |||
public class SliderTest extends LegacyAbstractFieldTest<Slider> { | |||
private Command<Slider, Double> minCommand = new Command<Slider, Double>() { | |||
@Override | |||
public void execute(Slider c, Double value, Object data) { | |||
c.setMin(value); | |||
} | |||
}; | |||
private Command<Slider, Double> maxCommand = new Command<Slider, Double>() { | |||
@Override | |||
public void execute(Slider c, Double value, Object data) { | |||
c.setMax(value); | |||
} | |||
}; | |||
private Command<Slider, SliderOrientation> orientationCommand = new Command<Slider, SliderOrientation>() { | |||
@Override | |||
public void execute(Slider c, SliderOrientation value, Object data) { | |||
c.setOrientation(value); | |||
} | |||
}; | |||
private Command<Slider, Integer> resolutionCommand = new Command<Slider, Integer>() { | |||
@Override | |||
public void execute(Slider c, Integer value, Object data) { | |||
c.setResolution(value); | |||
} | |||
}; | |||
@Override | |||
protected Class<Slider> getTestClass() { | |||
return Slider.class; | |||
} | |||
@Override | |||
protected void createActions() { | |||
super.createActions(); | |||
createMinSelect(CATEGORY_FEATURES); | |||
createMaxSelect(CATEGORY_FEATURES); | |||
createResolutionSelect(CATEGORY_FEATURES); | |||
createOrientationSelect(CATEGORY_FEATURES); | |||
} | |||
private void createResolutionSelect(String category) { | |||
createSelectAction("Resolution", category, createIntegerOptions(10), | |||
"1", resolutionCommand); | |||
} | |||
private void createOrientationSelect(String category) { | |||
LinkedHashMap<String, SliderOrientation> options = new LinkedHashMap<String, SliderOrientation>(); | |||
options.put("Horizontal", SliderOrientation.HORIZONTAL); | |||
options.put("Vertical", SliderOrientation.VERTICAL); | |||
createSelectAction("Orientation", category, options, "Horizontal", | |||
orientationCommand); | |||
} | |||
private void createMaxSelect(String category) { | |||
createSelectAction("Max", category, createDoubleOptions(100), "0", | |||
maxCommand); | |||
} | |||
private void createMinSelect(String category) { | |||
createSelectAction("Min", category, createDoubleOptions(100), "0", | |||
minCommand); | |||
} | |||
} |
@@ -0,0 +1,44 @@ | |||
/* | |||
* 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.v7.tests.components.slider; | |||
import org.junit.Test; | |||
import org.openqa.selenium.By; | |||
import org.openqa.selenium.WebElement; | |||
import org.openqa.selenium.interactions.Actions; | |||
import com.vaadin.tests.tb3.MultiBrowserTest; | |||
public class SliderFeedbackTest extends MultiBrowserTest { | |||
@Test | |||
public void testValueGreaterThanMaxInt() { | |||
openTestURL(); | |||
WebElement handle = findElement(By.className("v-slider-handle")); | |||
new Actions(driver).dragAndDropBy(handle, 400, 0).perform(); | |||
testBench().waitForVaadin(); | |||
double value = Double.valueOf( | |||
findElement(By.className("v-slider-feedback")).getText()); | |||
// Allow for some tolerance due to, you guessed it, IE8 | |||
assertLessThan("Unexpected feedback value {1} < {0}", 505000000000.0, | |||
value); | |||
assertGreater("Unexpected feedback value {1} > {0}", 510000000000.0, | |||
value); | |||
} | |||
} |