/*
@VaadinApache2LicenseForJavaFiles@
*/
package com.vaadin.ui;
import java.util.Map;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Vaadin6Component;
/**
* A component for selecting a numerical value within a range.
*
* Example code:
* class MyPlayer extends CustomComponent implements ValueChangeListener {
*
* Label volumeIndicator = new Label();
* Slider slider;
*
* public MyPlayer() {
* VerticalLayout vl = new VerticalLayout();
* setCompositionRoot(vl);
* slider = new Slider("Volume", 0, 100);
* slider.setImmediate(true);
* slider.setValue(new Double(50));
* vl.addComponent(slider);
* vl.addComponent(volumeIndicator);
* volumeIndicator.setValue("Current volume:" + 50.0);
* slider.addListener(this);
*
* }
*
* public void setVolume(double d) {
* volumeIndicator.setValue("Current volume: " + d);
* }
*
* public void valueChange(ValueChangeEvent event) {
* Double d = (Double) event.getProperty().getValue();
* setVolume(d.doubleValue());
* }
* }
*
*
*
* @author Vaadin Ltd.
*/
public class Slider extends AbstractField implements Vaadin6Component {
public static final int ORIENTATION_HORIZONTAL = 0;
public static final int ORIENTATION_VERTICAL = 1;
/** Minimum value of slider */
private double min = 0;
/** Maximum value of slider */
private double max = 100;
/**
* Resolution, how many digits are considered relevant after the decimal
* point. Must be a non-negative value
*/
private int resolution = 0;
/**
* Slider orientation (horizontal/vertical), defaults .
*/
private int orientation = ORIENTATION_HORIZONTAL;
/**
* Default slider constructor. Sets all values to defaults and the slide
* handle at minimum value.
*
*/
public Slider() {
super();
super.setValue(new Double(min));
}
/**
* 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();
setMin(min);
setMax(max);
setResolution(resolution);
}
/**
* 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);
}
/**
* Gets the maximum slider value
*
* @return the largest value the slider can have
*/
public double getMax() {
return max;
}
/**
* 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) {
this.max = max;
if (getValue() > max) {
setValue(max);
}
requestRepaint();
}
/**
* Gets the minimum slider value
*
* @return the smallest value the slider can have
*/
public double getMin() {
return min;
}
/**
* 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 max
* The new minimum slider value
*/
public void setMin(double min) {
this.min = min;
if (getValue() < min) {
setValue(min);
}
requestRepaint();
}
/**
* Get the current orientation of the slider (horizontal or vertical).
*
* @return {@link #ORIENTATION_HORIZONTAL} or
* {@link #ORIENTATION_HORIZONTAL}
*/
public int getOrientation() {
return orientation;
}
/**
* Set the orientation of the slider.
*
* @param The
* new orientation, either {@link #ORIENTATION_HORIZONTAL} or
* {@link #ORIENTATION_VERTICAL}
*/
public void setOrientation(int orientation) {
this.orientation = orientation;
requestRepaint();
}
/**
* Get the current resolution of the slider. The resolution is the number of
* digits after the decimal point.
*
* @return resolution
*/
public int getResolution() {
return resolution;
}
/**
* Set a new resolution for the slider. The resolution is the number of
* digits after the decimal point.
*
* @param resolution
*/
public void setResolution(int resolution) {
if (resolution < 0) {
return;
}
this.resolution = resolution;
requestRepaint();
}
/**
* 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) {
final double v = value.doubleValue();
double newValue;
if (resolution > 0) {
// Round up to resolution
newValue = (int) (v * Math.pow(10, resolution));
newValue = newValue / Math.pow(10, resolution);
if (min > newValue || max < newValue) {
throw new ValueOutOfBoundsException(value);
}
} else {
newValue = (int) v;
if (min > newValue || max < newValue) {
throw new ValueOutOfBoundsException(value);
}
}
super.setValue(newValue, repaintIsNotNeeded);
}
@Override
public void setValue(Object newFieldValue)
throws com.vaadin.data.Property.ReadOnlyException {
if (newFieldValue != null && newFieldValue instanceof Number
&& !(newFieldValue instanceof Double)) {
// Support setting all types of Numbers
newFieldValue = ((Number) newFieldValue).doubleValue();
}
super.setValue(newFieldValue);
}
@Override
public void paintContent(PaintTarget target) throws PaintException {
target.addAttribute("min", min);
if (max > min) {
target.addAttribute("max", max);
} else {
target.addAttribute("max", min);
}
target.addAttribute("resolution", resolution);
if (resolution > 0) {
target.addVariable(this, "value", getValue().doubleValue());
} else {
target.addVariable(this, "value", getValue().intValue());
}
if (orientation == ORIENTATION_VERTICAL) {
target.addAttribute("vertical", true);
}
}
/**
* Invoked when the value of a variable has changed. Slider listeners are
* notified if the slider value has changed.
*
* @param source
* @param variables
*/
@Override
public void changeVariables(Object source, Map variables) {
if (variables.containsKey("value")) {
final Object value = variables.get("value");
final Double newValue = new Double(value.toString());
if (newValue != null && newValue != getValue()
&& !newValue.equals(getValue())) {
try {
setValue(newValue, true);
} catch (final ValueOutOfBoundsException e) {
// Convert to nearest bound
double out = e.getValue().doubleValue();
if (out < min) {
out = min;
}
if (out > max) {
out = max;
}
super.setValue(new Double(out), false);
}
}
}
}
/**
* 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 ValueOutOfBoundsException
with the
* specified detail message.
*
* @param valueOutOfBounds
*/
public ValueOutOfBoundsException(Double valueOutOfBounds) {
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 getType() {
return Double.class;
}
}