/** * 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.ui.port.nxmblocks; import gov.redhawk.sca.util.ArrayUtil; import gov.redhawk.ui.port.nxmblocks.FftNxmBlockSettings.OutputType; import gov.redhawk.ui.port.nxmblocks.FftNxmBlockSettings.WindowType; import org.apache.commons.math.transform.FastFourierTransformer; import org.eclipse.core.databinding.Binding; import org.eclipse.core.databinding.DataBindingContext; import org.eclipse.core.databinding.UpdateValueStrategy; import org.eclipse.core.databinding.beans.PojoProperties; import org.eclipse.core.databinding.observable.value.IObservableValue; import org.eclipse.core.databinding.validation.ValidationStatus; import org.eclipse.core.runtime.IStatus; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jface.databinding.fieldassist.ControlDecorationSupport; import org.eclipse.jface.databinding.swt.WidgetProperties; import org.eclipse.jface.databinding.viewers.ViewerProperties; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ComboViewer; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; /** * Adjust/override FFT settings user entry dialog. * @noreference This class is provisional/beta and is subject to API changes * @since 4.4 */ public class FftNxmBlockControls { private static final Object[] FFT_SIZE_COMBO_VALUES = new Object[] { 1024, 2048, 4096, 8192, 16384, 32768 }; private static final String FFT_SIZE_FIELD_NAME = "Transform Size"; private static final String OVERLAP_FIELD_NAME = "Percent Overlap"; private static final String NUM_AVERAGES_FIELD_NAME = "Num Averages"; private static final String SLIDING_NUM_AVERAGES_FIELD_NAME = "Sliding Num Averages"; private final FftNxmBlockSettings settings; private DataBindingContext dataBindingCtx; private ComboViewer transformSizeField; private Text overlapField; private Text numAveragesField; private Text slidingNumAveragesField; private ComboViewer fftType; private ComboViewer fftWindow; public FftNxmBlockControls(@NonNull final FftNxmBlockSettings settings, @NonNull final DataBindingContext dataBindingsCtx) { this.settings = settings; this.dataBindingCtx = dataBindingsCtx; } public void createControls(@NonNull final Composite container) { container.setLayout(new GridLayout(2, false)); Label label; // === FFT transform size === label = new Label(container, SWT.NONE); label.setText(FftNxmBlockControls.FFT_SIZE_FIELD_NAME + ":"); this.transformSizeField = new ComboViewer(container, SWT.BORDER); // writable this.transformSizeField.getCombo().setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create()); this.transformSizeField.getCombo().setToolTipText("Performance is best if factorable by 2, 3, 4 and 5."); this.transformSizeField.setContentProvider(ArrayContentProvider.getInstance()); // ArrayContentProvider does not store any state, therefore can re-use instances this.transformSizeField.setLabelProvider(new LabelProvider()); Object[] inputValues = ArrayUtil.copyAndPrependIfNotNull(this.settings.getTransformSize(), FftNxmBlockControls.FFT_SIZE_COMBO_VALUES); this.transformSizeField.setInput(inputValues); this.transformSizeField.setSelection(new StructuredSelection(inputValues[0])); // select first value (which is current value or default) // === percent overlap === label = new Label(container, SWT.NONE); label.setText(FftNxmBlockControls.OVERLAP_FIELD_NAME + ":"); this.overlapField = new Text(container, SWT.BORDER); this.overlapField.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create()); this.overlapField.setText(Integer.toString(this.settings.getOverlap())); // === num averages (NAVG=) === label = new Label(container, SWT.NONE); label.setText(FftNxmBlockControls.NUM_AVERAGES_FIELD_NAME + ":"); this.numAveragesField = new Text(container, SWT.BORDER); this.numAveragesField.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create()); this.numAveragesField.setText(Integer.toString(this.settings.getNumAverages())); this.numAveragesField.setToolTipText("Avoid using large value as it will cause highlighted energy to remain longer."); // === num sliding averages (/NEXP=) === label = new Label(container, SWT.NONE); label.setText(FftNxmBlockControls.SLIDING_NUM_AVERAGES_FIELD_NAME + ":"); this.slidingNumAveragesField = new Text(container, SWT.BORDER); this.slidingNumAveragesField.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create()); this.slidingNumAveragesField.setText(Integer.toString(this.settings.getNumExpAverages())); this.slidingNumAveragesField.setToolTipText("Avoid using large value as it will cause highlighted energy to remain longer."); // === FFT output type === label = new Label(container, SWT.NONE); label.setText("Output Type:"); this.fftType = new ComboViewer(container, SWT.READ_ONLY); fftType.getCombo().setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create()); fftType.setContentProvider(ArrayContentProvider.getInstance()); // ArrayContentProvider does not store any state, therefore can re-use instances fftType.setLabelProvider(new LabelProvider() { @Override public String getText(Object element) { return ((FftNxmBlockSettings.OutputType) element).getLabel(); } }); fftType.setInput(FftNxmBlockSettings.OutputType.getStandardTypes()); OutputType currentOutputType = this.settings.getOutputType(); if (currentOutputType == null) { currentOutputType = OutputType.NORMAL; settings.setOutputType(currentOutputType); } fftType.setSelection(new StructuredSelection(currentOutputType)); // === FFT Window === label = new Label(container, SWT.NONE); label.setText("Window:"); fftWindow = new ComboViewer(container, SWT.READ_ONLY); fftWindow.getCombo().setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create()); fftWindow.setContentProvider(ArrayContentProvider.getInstance()); // ArrayContentProvider does not store any state, therefore can re-use instances fftWindow.setLabelProvider(new LabelProvider() { @Override public String getText(Object element) { return ((FftNxmBlockSettings.WindowType) element).getLabel(); } }); fftWindow.setInput(FftNxmBlockSettings.WindowType.values()); WindowType windowType = this.settings.getWindow(); if (windowType == null) { windowType = WindowType.HANNING; // default to Hanning Window Type settings.setWindow(windowType); } fftWindow.setSelection(new StructuredSelection(windowType)); initDataBindings(); } @SuppressWarnings({ "rawtypes", "unchecked" }) private void initDataBindings() { Binding bindingValue; IObservableValue fftSizeWidgetValue = WidgetProperties.selection().observe(this.transformSizeField.getCombo()); IObservableValue fftSizeModelValue = PojoProperties.value(FftNxmBlockSettings.PROP_TRANSFORM_SIZE).observe(this.settings); UpdateValueStrategy fftSizeTargetToModel = new UpdateValueStrategy(); fftSizeTargetToModel.setAfterConvertValidator(new FftSizeValidator(FftNxmBlockControls.FFT_SIZE_FIELD_NAME, 2)); bindingValue = dataBindingCtx.bindValue(fftSizeWidgetValue, fftSizeModelValue, fftSizeTargetToModel, null); ControlDecorationSupport.create(bindingValue, SWT.TOP | SWT.LEFT); IObservableValue overlapWidgetValue = WidgetProperties.text(SWT.Modify).observe(this.overlapField); IObservableValue overlapModelValue = PojoProperties.value(FftNxmBlockSettings.PROP_OVERLAP).observe(this.settings); UpdateValueStrategy overlapTargetToModel = new UpdateValueStrategy(); overlapTargetToModel.setAfterConvertValidator(new NumberRangeValidator<Integer>(FftNxmBlockControls.OVERLAP_FIELD_NAME, Integer.class, 0, 100)); bindingValue = dataBindingCtx.bindValue(overlapWidgetValue, overlapModelValue, overlapTargetToModel, null); ControlDecorationSupport.create(bindingValue, SWT.TOP | SWT.LEFT); IObservableValue numAvgWidgetValue = WidgetProperties.text(SWT.Modify).observe(this.numAveragesField); IObservableValue numAvgModelValue = PojoProperties.value(FftNxmBlockSettings.PROP_NUM_AVERAGES).observe(this.settings); UpdateValueStrategy numAvgTargetToModel = new UpdateValueStrategy(); numAvgTargetToModel.setAfterConvertValidator(new NumberRangeValidator<Integer>(FftNxmBlockControls.NUM_AVERAGES_FIELD_NAME, Integer.class, 0, false)); bindingValue = dataBindingCtx.bindValue(numAvgWidgetValue, numAvgModelValue, numAvgTargetToModel, null); ControlDecorationSupport.create(bindingValue, SWT.TOP | SWT.LEFT); IObservableValue numExpAvgWidgetValue = WidgetProperties.text(SWT.Modify).observe(this.slidingNumAveragesField); IObservableValue numExpAvgModelValue = PojoProperties.value(FftNxmBlockSettings.PROP_SLIDING_NUM_AVERAGES).observe(this.settings); UpdateValueStrategy numExpAvgTargetToModel = new UpdateValueStrategy(); numAvgTargetToModel.setAfterConvertValidator(new NumberRangeValidator<Integer>(FftNxmBlockControls.SLIDING_NUM_AVERAGES_FIELD_NAME, Integer.class, 0, false)); bindingValue = dataBindingCtx.bindValue(numExpAvgWidgetValue, numExpAvgModelValue, numExpAvgTargetToModel, null); ControlDecorationSupport.create(bindingValue, SWT.TOP | SWT.LEFT); IObservableValue outputTypeWidgetValue = ViewerProperties.singleSelection().observe(this.fftType); IObservableValue outputTypeModelValue = PojoProperties.value(FftNxmBlockSettings.PROP_OUTPUT_TYPE).observe(this.settings); bindingValue = dataBindingCtx.bindValue(outputTypeWidgetValue, outputTypeModelValue); ControlDecorationSupport.create(bindingValue, SWT.TOP | SWT.LEFT); IObservableValue windowWidgetValue = ViewerProperties.singleSelection().observe(this.fftWindow); IObservableValue windowModelValue = PojoProperties.value(FftNxmBlockSettings.PROP_WINDOW_TYPE).observe(this.settings); bindingValue = dataBindingCtx.bindValue(windowWidgetValue, windowModelValue); ControlDecorationSupport.create(bindingValue, SWT.TOP | SWT.LEFT); } static class FftSizeValidator extends NumberRangeValidator<Integer> { static final int LARGE_SIZE_TO_WARN = 1048576; // 1M public FftSizeValidator(String fieldName, Integer minValue) { super(fieldName, Integer.class, minValue, null); } @Override protected IStatus validateValueAfter(Integer val) { if (!FastFourierTransformer.isPowerOf2(val)) { return ValidationStatus.warning(getFieldName() + " is not a power of 2 and may be invalid"); } else if (val > FftSizeValidator.LARGE_SIZE_TO_WARN) { return ValidationStatus.warning(getFieldName() + " is very large which requires more time to process and display data"); } return ValidationStatus.ok(); } } // end class FftSizeValidator }