/*
* Copyright (c) 2007 Stiftung Deutsches Elektronen-Synchrotron,
* Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
*
* THIS SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "../AS IS" BASIS.
* WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. SHOULD THE SOFTWARE PROVE DEFECTIVE
* IN ANY RESPECT, THE USER ASSUMES THE COST OF ANY NECESSARY SERVICING, REPAIR OR
* CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
* NO USE OF ANY SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
* DESY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
* OR MODIFICATIONS.
* THE FULL LICENSE SPECIFYING FOR THE SOFTWARE THE REDISTRIBUTION, MODIFICATION,
* USAGE AND OTHER RIGHTS AND OBLIGATIONS IS INCLUDED WITH THE DISTRIBUTION OF THIS
* PROJECT IN THE FILE LICENSE.HTML. IF THE LICENSE IS NOT INCLUDED YOU MAY FIND A COPY
* AT HTTP://WWW.DESY.DE/LEGAL/LICENSE.HTM
*/
package org.csstudio.sds.components.ui.internal.editparts;
import java.math.BigDecimal;
import java.math.MathContext;
import org.csstudio.sds.components.model.ThumbWheelModel;
import org.csstudio.sds.components.ui.internal.figures.RefreshableThumbWheelFigure;
import org.csstudio.sds.components.ui.internal.figures.RefreshableThumbWheelFigure.WheelListener;
import org.csstudio.sds.ui.editparts.AbstractWidgetEditPart;
import org.csstudio.sds.ui.editparts.ExecutionMode;
import org.csstudio.sds.ui.editparts.IWidgetPropertyChangeHandler;
import org.eclipse.draw2d.IFigure;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
/**
* Controller for the ThumbWheel.
*
* @author Alen Vrecko
*
*/
public class ThumbWheelEditPart extends AbstractWidgetEditPart {
private ThumbWheelLogic _logic;
private ThumbWheelModel _model;
private RefreshableThumbWheelFigure _figure;
/**
* {@inheritDoc}
*/
@Override
protected final IFigure doCreateFigure() {
_model = (ThumbWheelModel) getWidgetModel();
_logic = new ThumbWheelLogic(_model.getValue(), _model
.getWholePartDigits(), _model.getDecimalPartDigits());
_logic.setMax(_model.getMax());
_logic.setMin(_model.getMin());
_figure = new RefreshableThumbWheelFigure(_logic.getIntegerWheels(),
_logic.getDecimalWheels());
_model.setWholePartDigits(_logic.getIntegerWheels());
_model.setDecimalPartDigits(_logic.getDecimalWheels());
_figure.setWheelFonts(getModelFont(ThumbWheelModel.PROP_FONT));
_figure.setInternalBorderColor(getModelColor(ThumbWheelModel.PROP_INTERNAL_FRAME_COLOR));
_figure.setInternalBorderThickness(_model.getInternalBorderWidth());
_figure.addWheelListener(new WheelListener() {
@Override
public void decrementDecimalPart(int index) {
if (getExecutionMode() == ExecutionMode.RUN_MODE) {
_logic.decrementDecimalDigitAt(index);
updateWheelValues();
_model.setManualValue(_logic.getValue());
}
}
@Override
public void incrementDecimalPart(int index) {
if (getExecutionMode() == ExecutionMode.RUN_MODE) {
_logic.incrementDecimalDigitAt(index);
updateWheelValues();
_model.setManualValue(_logic.getValue());
}
}
@Override
public void decrementIntegerPart(int index) {
if (getExecutionMode() == ExecutionMode.RUN_MODE) {
_logic.decrementIntigerDigitAt(index);
updateWheelValues();
_model.setManualValue(_logic.getValue());
}
}
@Override
public void incrementIntegerPart(int index) {
if (getExecutionMode() == ExecutionMode.RUN_MODE) {
_logic.incrementIntigerWheel(index);
updateWheelValues();
_model.setManualValue(_logic.getValue());
}
}
});
updateWheelValues();
return _figure;
}
private void updateWheelValues() {
// update all wheels
int limit = _model.getWholePartDigits();
for (int i = 0; i < limit; i++) {
_figure.setIntegerWheel(i, _logic.getIntegerDigitAt(i));
}
limit = _model.getDecimalPartDigits();
for (int i = 0; i < limit; i++) {
_figure.setDecimalWheel(i, _logic.getDecimalDigitAt(i));
}
// update minus sign
if (_logic.getValue() < 0) {
_figure.showMinus(true);
} else {
_figure.showMinus(false);
}
_figure.revalidate();
}
/**
* {@inheritDoc}
*/
@Override
protected final void registerPropertyChangeHandlers() {
// decimal wheels
setPropertyChangeHandler(ThumbWheelModel.PROP_DECIMAL_DIGITS_PART,
getPropDecimalDigitdPart());
// integer wheels
setPropertyChangeHandler(ThumbWheelModel.PROP_WHOLE_DIGITS_PART,
getPropWholeDigitsPart());
// min
setPropertyChangeHandler(ThumbWheelModel.PROP_MIN, getPropMax());
// max
setPropertyChangeHandler(ThumbWheelModel.PROP_MAX, getPropMin());
// value
setPropertyChangeHandler(ThumbWheelModel.PROP_VALUE, getPropValue());
// font
setPropertyChangeHandler(ThumbWheelModel.PROP_FONT, new FontChangeHandler<RefreshableThumbWheelFigure>(){
@Override
protected void doHandle(RefreshableThumbWheelFigure figure, Font font) {
figure.setWheelFonts(font);
}
});
// border color
setPropertyChangeHandler(ThumbWheelModel.PROP_INTERNAL_FRAME_COLOR,
new ColorChangeHandler<RefreshableThumbWheelFigure>(){
@Override
protected void doHandle(RefreshableThumbWheelFigure figure, Color color) {
figure.setInternalBorderColor(color);
}
});
// border width
setPropertyChangeHandler(ThumbWheelModel.PROP_INTERNAL_FRAME_THICKNESS,
getPropBorderWidth());
}
/**
* @return
*/
private IWidgetPropertyChangeHandler getPropBorderWidth() {
IWidgetPropertyChangeHandler handler = new IWidgetPropertyChangeHandler() {
@Override
public boolean handleChange(final Object oldValue,
final Object newValue, final IFigure refreshableFigure) {
RefreshableThumbWheelFigure figure = (RefreshableThumbWheelFigure) refreshableFigure;
figure.setInternalBorderThickness((Integer) newValue);
return true;
}
};
return handler;
}
/**
* @return
*/
private IWidgetPropertyChangeHandler getPropValue() {
IWidgetPropertyChangeHandler handler = new IWidgetPropertyChangeHandler() {
@Override
public boolean handleChange(final Object oldValue,
final Object newValue, final IFigure refreshableFigure) {
_logic.setValue((Double) newValue);
updateWheelValues();
return true;
}
};
return handler;
}
/**
* @return
*/
private IWidgetPropertyChangeHandler getPropMin() {
IWidgetPropertyChangeHandler handler = new IWidgetPropertyChangeHandler() {
@Override
public boolean handleChange(final Object oldValue,
final Object newValue, final IFigure refreshableFigure) {
_logic.setMax((Double) newValue);
updateWheelValues();
return true;
}
};
return handler;
}
/**
* @return
*/
private IWidgetPropertyChangeHandler getPropMax() {
IWidgetPropertyChangeHandler handler = new IWidgetPropertyChangeHandler() {
@Override
public boolean handleChange(final Object oldValue,
final Object newValue, final IFigure refreshableFigure) {
_logic.setMin((Double) newValue);
updateWheelValues();
return true;
}
};
return handler;
}
/**
* @return
*/
private IWidgetPropertyChangeHandler getPropWholeDigitsPart() {
IWidgetPropertyChangeHandler handler = new IWidgetPropertyChangeHandler() {
@Override
public boolean handleChange(final Object oldValue,
final Object newValue, final IFigure refreshableFigure) {
RefreshableThumbWheelFigure figure = (RefreshableThumbWheelFigure) refreshableFigure;
_logic.setIntegerWheels((Integer) newValue);
figure.setWholeDigitsPart(_logic.getIntegerWheels());
_model.setWholePartDigits(_logic.getIntegerWheels());
updateWheelValues();
return true;
}
};
return handler;
}
/**
* @return
*/
private IWidgetPropertyChangeHandler getPropDecimalDigitdPart() {
IWidgetPropertyChangeHandler handler = new IWidgetPropertyChangeHandler() {
@Override
public boolean handleChange(final Object oldValue,
final Object newValue, final IFigure refreshableFigure) {
RefreshableThumbWheelFigure figure = (RefreshableThumbWheelFigure) refreshableFigure;
_logic.setDecimalWheels((Integer) newValue);
figure.setDecimalDigitsPart(_logic.getDecimalWheels());
_model.setDecimalPartDigits(_logic.getDecimalWheels());
updateWheelValues();
return true;
}
};
return handler;
}
/**
* Thumb wheel widgets are always disabled in edit mode.
* @return true as always disabled.
*/
@Override
protected final boolean forceDisabledInEditMode() {
return true;
}
/**
* Represents the "brain" behind the ThumbWheel. It represents the wheel and
* its values. Integer wheels are indexed from right to left. Decimal wheels
* are indexed left to right from the decimal point.
*
* <p>
* Note the inherent precision of value double is 15 decimal places
* therefore you cannot have more than 15 wheels.
* <p>
*
* @author Alen Vrecko
*
*/
private static class ThumbWheelLogic {
private static final char BEYOND_LIMIT_CHAR = 'X';
private BigDecimal value;
private int integerWheels;
private int decimalWheels;
private BigDecimal _max = null;
private BigDecimal _min = null;
private BigDecimal wheelMax;
private BigDecimal wheelMin;
public static final int WHEEL_LIMIT = 15;
public ThumbWheelLogic(double value, int integerWheels,
int decimalWheels) {
setValue(value);
setIntegerWheels(integerWheels);
setDecimalWheels(decimalWheels);
}
/**
* Increments the integer digit on a specific index. E.g. on 567.12
* calling increment for - 0 will set the value to 568.12, with index -
* 2 will result in 667.12. Will not set beyond max value.
*
* @param index
* @param val
*/
public void incrementIntigerWheel(int index) {
increment(index, "1E");
}
/**
* Increments the decimal digit on a specific index. E.g. on 567.12
* calling increment for - 0 will set the value to 567.22, with index -
* 1 will result in 567.11. Will not go bellow max value.
*
* @param index
* @param val
*/
public void incrementDecimalDigitAt(int index) {
increment(index, "0.1E-");
}
private boolean isZero(BigDecimal num) {
return num.signum() == 0;
}
private boolean equalSign(BigDecimal a, BigDecimal b) {
return a.signum() == b.signum();
}
private boolean greater(BigDecimal a, BigDecimal b) {
if (b == null) {
return false;
}
return a.compareTo(b) > 0;
}
private boolean less(BigDecimal a, BigDecimal b) {
if (b == null) {
return false;
}
return a.compareTo(b) < 0;
}
private void increment(int index, String numberGenerator) {
// generate new number using the string ("1E" or "1E-" or similar)
BigDecimal decrementor = new BigDecimal(numberGenerator + index,
MathContext.UNLIMITED);
BigDecimal newValue = value.add(decrementor);
// handle over the zero handling
if (!isZero(newValue) && !equalSign(value, newValue)) {
newValue = value.negate().add(decrementor);
}
// if value is already beyond the upper limit or upper wheel limit
// just ignore the request
if ((_max != null && greater(value, _max))
|| greater(value, wheelMax)) {
return;
}
// if we are below lower limit just drop to lower limit
if (less(value, _min)) {
value = _min;
} else if (less(value, wheelMin)) {
value = wheelMin;
}
// if we are incrementing above the wheel upper limit just set to
// wheel upper limit
else if (greater(newValue, wheelMax)) {
value = wheelMax;
}
// if we are incrementing beyond the upper limit just set to upper
// limit
else if (_max != null && greater(newValue, _max)) {
value = _max;
} else {
value = newValue;
}
}
/**
* Decrements the integer digit on a specific index. E.g. on 567.12
* calling increment for - 0 will set the value to 468.12, with index -
* 2 will result in 467.12. Will not go below min value.
*
* @param index
* @param val
*/
public void decrementIntigerDigitAt(int index) {
decrement(index, "-1E");
}
/**
* Decrements the decimal digit on a specific index. E.g. on 567.12
* calling increment for - 0 will set the value to 568.02, with index -
* 1 will result in 567.11. Will not go bellow min value.
*
* @param index
* @param val
*/
public void decrementDecimalDigitAt(int index) {
decrement(index, "-0.1E-");
}
private void decrement(int index, String numberGenerator) {
// generate new number using the string ("1E" or "1E-" or similar)
BigDecimal decrementor = new BigDecimal(numberGenerator + index,
MathContext.UNLIMITED);
BigDecimal newValue = value.add(decrementor);
// handle over the zero handling
if (!isZero(newValue) && !equalSign(value, newValue)) {
newValue = value.negate().add(decrementor);
}
// if value is already beyond the lower limit or lower wheel limit
// just ignore the request
if ((_min != null && less(value, _min)) || less(value, wheelMin)) {
return;
}
// if we are beyond upper limit just drop to upper limit
if (greater(value, _max)) {
value = _max;
} else if (greater(value, wheelMax)) {
value = wheelMax;
}
// if we are decrementing below the lower limit just set to lower
// limit
else if (_min != null && less(newValue, _min)) {
value = _min;
}
// if we are decrementing below the wheel lower limit just set to
// wheel lower limit
else if (less(newValue, wheelMin)) {
value = wheelMin;
}
else {
value = newValue;
}
}
/**
* Returns a digit in the specified index. E.g. for 324.23 getting index
* 0,1,2 would return 4,2,3. If the number is beyond max in will return
* proper digit of max. Same goes for min.
*
* @param index
* @return
*/
public char getIntegerDigitAt(int index) {
// check if number is beyond inherent wheel limit
if (beyondDisplayLimit()) {
return BEYOND_LIMIT_CHAR;
}
String plainString = value.toPlainString();
// get rid of decimal part
int dot = plainString.indexOf('.');
if (dot >= 0) {
plainString = plainString.substring(0, dot);
}
// get rid of leading minus
if (plainString.startsWith("-")) {
plainString = plainString.substring(1);
}
if (index >= plainString.length()) {
return '0';
}
return plainString.charAt(plainString.length() - 1 - index);
}
/**
* Returns a digit in the specified index. E.g. for 324.23 getting index
* 0,1 would return 2,3.
*
* @param index
* @return
*/
public char getDecimalDigitAt(int index) {
// check if number is beyond inherent wheel limit
if (beyondDisplayLimit()) {
return BEYOND_LIMIT_CHAR;
}
String plainString = value.toPlainString();
if (plainString.indexOf('.') < 0) {
return '0';
}
plainString = plainString.substring(plainString.indexOf('.') + 1);
if (index >= plainString.length()) {
return '0';
}
return plainString.charAt(index);
}
/**
* Returns true if the value is bigger than the wheels can represent.
*
* @return
*/
public boolean beyondDisplayLimit() {
return greater(value, wheelMax) || less(value, wheelMin);
}
public void setMax(Double max) {
this._max = Double.isNaN(max) ? null : new BigDecimal(Double
.toString(max), MathContext.UNLIMITED);
}
public void setMin(Double min) {
this._min = Double.isNaN(min) ? null : new BigDecimal(Double
.toString(min), MathContext.UNLIMITED);
}
public int getIntegerWheels() {
return integerWheels;
}
public void setIntegerWheels(int integerWheels) {
if (integerWheels + decimalWheels > WHEEL_LIMIT) {
this.integerWheels = WHEEL_LIMIT - decimalWheels;
return;
}
this.integerWheels = integerWheels;
String nines = "";
for (int i = 0; i < integerWheels; i++) {
nines += "9";
}
if (decimalWheels > 0) {
nines += ".";
for (int i = 0; i < decimalWheels; i++) {
nines += "9";
}
}
wheelMax = new BigDecimal(nines, MathContext.UNLIMITED);
wheelMin = new BigDecimal("-" + nines, MathContext.UNLIMITED);
}
public int getDecimalWheels() {
return decimalWheels;
}
public void setDecimalWheels(int decimalWheels) {
if (integerWheels + decimalWheels > WHEEL_LIMIT) {
this.decimalWheels = WHEEL_LIMIT - integerWheels;
return;
}
this.decimalWheels = decimalWheels;
String nines = "";
if (integerWheels > 0) {
for (int i = 0; i < integerWheels; i++) {
nines += "9";
}
} else {
nines += "0";
}
nines += ".";
for (int i = 0; i < decimalWheels; i++) {
nines += "9";
}
wheelMax = new BigDecimal(nines, MathContext.UNLIMITED);
wheelMin = new BigDecimal("-" + nines, MathContext.UNLIMITED);
}
public double getValue() {
return value.doubleValue();
}
public void setValue(double value) {
setValue(Double.toString(value));
}
public void setValue(String value) {
this.value = new BigDecimal(value, MathContext.UNLIMITED);
}
}
}