/**
* This file is protected by Copyright.
* Please refer to the COPYRIGHT file distributed with this source distribution.
*
* This file is part of REDHAWK IDE.
*
* All rights reserved. This program and the accompanying materials are made available under
* the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html.
*
*/
package gov.redhawk.sca.waveform.controlpanel.propertyEditors;
import gov.redhawk.common.ui.widgets.Dval;
import gov.redhawk.model.sca.ScaPackage;
import gov.redhawk.model.sca.ScaSimpleProperty;
import gov.redhawk.sca.ui.compatibility.CompatibilityUtil;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import mil.jpeojtrs.sca.prf.Enumeration;
import mil.jpeojtrs.sca.prf.Enumerations;
import mil.jpeojtrs.sca.prf.Range;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.emf.databinding.EMFDataBindingContext;
import org.eclipse.emf.databinding.EMFObservables;
import org.eclipse.jface.databinding.swt.ISWTObservableValue;
import org.eclipse.jface.databinding.swt.WidgetProperties;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
public class DecimalPropertyEditor< T extends Number > extends PropertyEditor {
private static final double INCR_1 = 0.1;
private static final double INCR_2 = 5;
private static final double INCR_3 = 10;
private static final double MIN_1 = 10;
private static final double MIN_2 = 100;
private static final double PAGE_INCR_MULTIPLIER = 5;
private static final double MAX_VALUE_NO_SCI_NOTATION = 10E6;
private static final double IBCR_0 = 1000;
private static final int UPDATE_DELAY_MS = 200;
private final String name;
private Number value;
private Control control;
private final ScaSimpleProperty prop;
private Dval dval;
private final DecimalFormat form = (DecimalFormat) NumberFormat.getInstance();
private Class<T> valueType;
private EMFDataBindingContext context;
private ComboViewer enumViewer;
private class DecimalUpdateValueStrategy extends UpdateValueStrategy {
@Override
public Object convert(final Object value) {
if (value instanceof Number) {
final String pattern = getFormatPattern();
DecimalPropertyEditor.this.form.applyPattern(pattern);
final Number d = (Number) value;
final String s = DecimalPropertyEditor.this.form.format(d);
try {
return DecimalPropertyEditor.this.form.parse(s);
} catch (final ParseException e) {
return value;
}
}
return value;
}
}
private class DecimalUpdateValueStrategy2 extends UpdateValueStrategy {
@Override
public Object convert(final Object value) {
if (value instanceof String) {
final String s = (String) value;
try {
final String pattern = getFormatPattern();
DecimalPropertyEditor.this.form.applyPattern(pattern);
if (DecimalPropertyEditor.this.valueType == Float.class) {
return DecimalPropertyEditor.this.form.parse(s).floatValue();
} else {
return DecimalPropertyEditor.this.form.parse(s).doubleValue();
}
} catch (final NumberFormatException e) {
return value;
} catch (final ParseException e) {
return value;
}
}
return value;
}
}
private class DecimalUpdateValueStrategy3 extends UpdateValueStrategy {
@Override
public Object convert(final Object value) {
if (value instanceof Number) {
final String pattern = getFormatPattern();
DecimalPropertyEditor.this.form.applyPattern(pattern);
final Number d = (Number) value;
final String s = DecimalPropertyEditor.this.form.format(d);
return s;
}
return value;
}
}
private class SelectionToLocalValueStrategy extends UpdateValueStrategy {
@Override
public Object convert(final Object value) {
if (value instanceof String) {
try {
final Enumeration enumer = getEnumFromLabel((String) value);
DecimalPropertyEditor.this.form.applyPattern(getFormatPattern());
return DecimalPropertyEditor.this.form.parse(enumer.getValue());
} catch (final ParseException e) {
return value;
}
}
return value;
}
}
private class LocalToSelectionValueStrategy extends UpdateValueStrategy {
@Override
public Object convert(final Object value) {
if (value instanceof Number) {
DecimalPropertyEditor.this.enumViewer.setSelection(new StructuredSelection(getEnumFromValue((Number) value)));
}
return value;
}
}
public Enumeration getEnumFromLabel(final String value) {
final Enumerations enumValues = (Enumerations) this.enumViewer.getInput();
for (final Enumeration enumer : enumValues.getEnumeration()) {
if (enumer.getLabel().equals(value)) {
return enumer;
}
}
return null;
}
public Object getEnumFromValue(final Number value) {
final Enumerations enumValues = (Enumerations) this.enumViewer.getInput();
for (final Enumeration enumer : enumValues.getEnumeration()) {
if (this.valueType == Double.class) {
final Double val = new Double(enumer.getValue());
if (val.doubleValue() == value.doubleValue()) {
return enumer;
}
} else if (this.valueType == Float.class) {
final Float val = new Float(enumer.getValue());
if (val.floatValue() == value.floatValue()) {
return enumer;
}
}
}
return value;
}
@SuppressWarnings("unchecked")
public DecimalPropertyEditor(final String name, final Number value, final ScaSimpleProperty prop) {
this.name = name;
this.value = value;
this.prop = prop;
if (value instanceof Float) {
this.valueType = (Class<T>) Float.class;
} else {
this.valueType = (Class<T>) Double.class;
}
}
public String getFormatPattern() {
String pattern = "";
if (this.value.doubleValue() > DecimalPropertyEditor.MAX_VALUE_NO_SCI_NOTATION) {
if (this.valueType == Float.class) {
pattern = "##0.###E0#";
} else {
pattern = "##0.######E0#";
}
} else {
pattern = "#######0.##";
}
if (this.dval != null) {
this.dval.applyFormat(pattern);
}
return pattern;
}
@Override
public void setupBindings() {
this.context = new EMFDataBindingContext();
if (this.enumViewer == null) {
final ScaSimplePropertyControl scaSimplePropertyControl = new ScaSimplePropertyControl(this.control, this.prop);
final ISWTObservableValue textObservable = WidgetProperties.text(new int[] { SWT.FocusOut, SWT.DefaultSelection }).observe(this.control);
this.context.bindValue(textObservable, scaSimplePropertyControl.getModel(), new DecimalUpdateValueStrategy2(), new DecimalUpdateValueStrategy3());
this.context.bindValue(WidgetProperties.text(SWT.Modify).observeDelayed(UPDATE_DELAY_MS, this.control), scaSimplePropertyControl.getEditingObserable());
this.context.bindValue(scaSimplePropertyControl.getTarget(), EMFObservables.observeValue(this.prop, ScaPackage.Literals.SCA_SIMPLE_PROPERTY__VALUE),
new DecimalUpdateValueStrategy(), new DecimalUpdateValueStrategy());
} else {
final ScaSimplePropertyControl scaSimplePropertyControl = new ScaSimplePropertyControl(this.enumViewer.getControl(), this.prop);
final ISWTObservableValue selectObservable = WidgetProperties.selection().observe(this.enumViewer.getCombo());
this.context.bindValue(selectObservable, scaSimplePropertyControl.getModel(), new SelectionToLocalValueStrategy(), new LocalToSelectionValueStrategy());
this.context.bindValue(WidgetProperties.selection().observe(this.enumViewer.getCombo()), scaSimplePropertyControl.getEditingObserable(),
new SelectionToLocalValueStrategy(), null);
this.context.bindValue(scaSimplePropertyControl.getTarget(), EMFObservables.observeValue(this.prop, ScaPackage.Literals.SCA_SIMPLE_PROPERTY__VALUE),
new DecimalUpdateValueStrategy(), null);
}
}
@Override
public void renderNameValuePair(final Composite parent) {
final Label label = new Label(parent, SWT.NONE);
GridDataFactory.fillDefaults().grab(false, false).applyTo(label);
label.setText(this.name);
final Range range = this.prop.getDefinition().getRange();
//Dval not working properly on RAP
if (range != null && !SWT.getPlatform().startsWith("rap")) {
this.dval = new Dval(parent, SWT.BORDER);
this.control = this.dval.getTextBox();
final Double min = Double.parseDouble(range.getMin());
final Double max = Double.parseDouble(range.getMax());
this.dval.applyFormat(getFormatPattern());
this.dval.setValue(this.value.doubleValue());
this.dval.setMinimum(min);
this.dval.setMaximum(max);
double incr = 0;
if (this.value.doubleValue() > DecimalPropertyEditor.MAX_VALUE_NO_SCI_NOTATION) {
incr = DecimalPropertyEditor.IBCR_0;
} else {
if (max - min < 1) {
incr = DecimalPropertyEditor.INCR_1;
} else if (max - min < DecimalPropertyEditor.MIN_1) {
incr = 1;
} else if (max - min < DecimalPropertyEditor.MIN_2) {
incr = DecimalPropertyEditor.INCR_2;
} else {
incr = DecimalPropertyEditor.INCR_3;
}
}
this.dval.setIncrement(incr);
this.dval.setPageIncrement(incr * DecimalPropertyEditor.PAGE_INCR_MULTIPLIER);
GridDataFactory.fillDefaults().grab(true, false).applyTo(this.dval);
} else {
final Enumerations values = this.prop.getDefinition().getEnumerations();
if (values == null || values.getEnumeration() == null || values.getEnumeration().size() == 0) {
this.control = new Text(parent, SWT.BORDER);
GridDataFactory.fillDefaults().grab(true, false).applyTo(this.control);
this.form.applyPattern(getFormatPattern());
((Text) this.control).setText(this.form.format(this.value));
} else {
this.enumViewer = new ComboViewer(parent, SWT.NONE);
CompatibilityUtil.disableComboWheelScrollSelect(enumViewer);
GridDataFactory.fillDefaults().grab(true, false).applyTo(this.enumViewer.getControl());
this.enumViewer.setContentProvider(new EnumValuesContentProvider());
this.enumViewer.setLabelProvider(new EnumValuesLabelProvider());
this.enumViewer.setInput(this.prop.getDefinition().getEnumerations());
this.enumViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(final SelectionChangedEvent event) {
final Enumeration sel = (Enumeration) ((StructuredSelection) event.getSelection()).getFirstElement();
DecimalPropertyEditor.this.form.applyPattern(getFormatPattern());
try {
DecimalPropertyEditor.this.value = DecimalPropertyEditor.this.form.parse(sel.getValue());
} catch (final ParseException e) {
//PASS
}
}
});
}
}
}
@Override
public void dispose() {
if (this.context != null) {
this.context.dispose();
}
}
}