org.janelia.it.venkman.gui.parameter.ParameterGroup.java Source code

Java tutorial

Introduction

Here is the source code for org.janelia.it.venkman.gui.parameter.ParameterGroup.java

Source

/*
 * Copyright (c) 2014 Howard Hughes Medical Institute.
 * All rights reserved.
 * Use is subject to Janelia Farm Research Campus Software Copyright 1.1
 * license terms (http://license.janelia.org/license/jfrc_copyright_1_1.html).
 */

package org.janelia.it.venkman.gui.parameter;

import com.jgoodies.forms.builder.DefaultFormBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import org.janelia.it.venkman.config.rules.BehaviorLimitedKinematicVariableFunction;
import org.janelia.it.venkman.config.rules.BehaviorLimitedKinematicVariableFunctionList;
import org.janelia.it.venkman.config.rules.IntensityValue;
import org.janelia.it.venkman.config.rules.KinematicVariableFunction;
import org.janelia.it.venkman.config.rules.LEDFlashPattern;
import org.janelia.it.venkman.config.rules.PositionalVariableFunction;
import org.janelia.it.venkman.config.rules.SingleVariableFunction;
import org.janelia.it.venkman.gui.NarrowOptionPane;
import org.janelia.it.venkman.gui.parameter.annotation.VenkmanParameter;
import org.janelia.it.venkman.gui.parameter.annotation.VenkmanParameterFilter;

import javax.swing.*;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Group of user interface parameters for a behavior or stimulus configuration.
 * Examines the behavior/stimulus class implementation's annotations to build
 * the appropriate user interface.
 *
 * @author Eric Trautman
 */
public class ParameterGroup<T> {

    private List<ExperimentParameter> parameterList;
    private T data;
    private JPanel contentPanel;

    public ParameterGroup(T data) throws IllegalArgumentException {

        this.parameterList = new ArrayList<ExperimentParameter>();
        this.data = data;

        Set<String> hiddenParameters = new HashSet<String>();
        VenkmanParameterFilter filter;
        Class<?> clazz = data.getClass();
        List<Class<?>> classList = new ArrayList<Class<?>>();
        while (clazz != null) {

            filter = clazz.getAnnotation(VenkmanParameterFilter.class);
            if (filter != null) {
                hiddenParameters.addAll(Arrays.asList(filter.hiddenParameters()));
            }

            classList.add(clazz);
            clazz = clazz.getSuperclass();
        }

        List<SortableAnnotationField> annotationFieldList = new ArrayList<SortableAnnotationField>();
        VenkmanParameter annotation;
        // reverse loop order so that super class parameters are added first by default
        for (int i = classList.size(); i > 0; i--) {
            clazz = classList.get(i - 1);
            for (Field f : clazz.getDeclaredFields()) {
                annotation = f.getAnnotation(VenkmanParameter.class);
                if ((annotation != null) && (!hiddenParameters.contains(f.getName()))) {
                    annotationFieldList.add(new SortableAnnotationField(annotation, f));
                }
            }
        }

        // sort list by annotated display order (to override default class order as needed)
        Collections.sort(annotationFieldList);

        // add each field (in the desired order) to the user interface
        for (SortableAnnotationField annotationField : annotationFieldList) {
            try {
                addParameter(annotationField.field, annotationField.annotation);
            } catch (Exception e) {
                final String fieldName = annotationField.field.getName();
                final String className = annotationField.field.getClass().getName();
                throw new IllegalArgumentException(
                        "Failed to add parameter for field " + fieldName + " in class " + className, e);
            }
        }
    }

    public T getData() {
        return data;
    }

    public JPanel getEditableContentPanel() {
        return getContentPanel(true);
    }

    public JPanel getContentPanel(boolean isEditable) {
        if (contentPanel == null) {
            FormLayout layout = new FormLayout("left:max(40dlu;pref), 4dlu, left:pref:none", // column layout
                    ""); // row layout
            DefaultFormBuilder builder = new DefaultFormBuilder(layout);
            //            builder.setDefaultRowSpec(RowSpec.decode("top:pref:none"));

            builder.setVAlignment(CellConstraints.TOP);

            if (parameterList.size() > 0) {

                for (ExperimentParameter parameter : parameterList) {
                    if (isEditable) {
                        builder.append(parameter.getDisplayName() + ":", parameter.getComponent());
                    } else {
                        builder.append(parameter.getDisplayName() + ":", parameter.getReadOnlyComponent());
                    }
                }
                builder.nextLine();

            } else {
                builder.append("There are no parameters to configure.");
            }

            contentPanel = builder.getPanel();
        }
        return contentPanel;
    }

    public boolean validate() {

        boolean allParametersValid = false;

        ExperimentParameter parameter = null;
        try {

            for (ExperimentParameter p : parameterList) {
                parameter = p;
                parameter.validate();
            }

            allParametersValid = true;

        } catch (IllegalArgumentException e) {
            if (parameter != null) {
                NarrowOptionPane.showMessageDialog(contentPanel, e.getMessage(), "Invalid Parameter",
                        JOptionPane.ERROR_MESSAGE);
                parameter.getComponent().requestFocus();
            }
        }

        return allParametersValid;
    }

    public void applyParameters() throws IllegalArgumentException, IllegalAccessException {
        for (ExperimentParameter parameter : parameterList) {
            parameter.applyValue(data);
        }
    }

    protected List<ExperimentParameter> getParameterList() {
        return parameterList;
    }

    private void addParameter(Field field, VenkmanParameter annotation)
            throws IllegalAccessException, NumberFormatException {

        field.setAccessible(true);

        ExperimentParameter parameter = null;

        final Class type = field.getType();
        if ((type == double.class) || (type == Double.class)) {

            DecimalParameter p = new DecimalParameter(annotation.displayName(), annotation.required(), field,
                    getBigDecimalValue(annotation.minimum()), getBigDecimalValue(annotation.maximum()));
            double v = field.getDouble(data);
            p.setDoubleValue(v);
            parameter = p;

        } else if ((type == long.class) || (type == Long.class) || (type == int.class) || (type == Integer.class)) {

            NumericParameter p = new NumericParameter(annotation.displayName(), annotation.required(), field,
                    getLongValue(annotation.minimum()), getLongValue(annotation.maximum()));
            long v = field.getLong(data);
            p.setValue(String.valueOf(v));
            parameter = p;

        } else if (type == boolean.class) {

            BooleanParameter p = new BooleanParameter(annotation.displayName(), annotation.required(), field);
            boolean v = field.getBoolean(data);
            p.setValue(v);
            parameter = p;

        } else if (type.isEnum()) {

            EnumeratedParameter p = new EnumeratedParameter(annotation.displayName(), annotation.required(), field);
            String v = String.valueOf(field.get(data));
            p.setValue(v);
            parameter = p;

        } else if (type == String.class) {

            VerifiedParameter p = new VerifiedParameter(annotation.displayName(), annotation.required(), field);
            String v = (String) field.get(data);
            p.setValue(v);
            parameter = p;

        } else if (type == LEDFlashPattern.class) {

            LEDFlashPatternParameter p = new LEDFlashPatternParameter(annotation.displayName(),
                    annotation.required(), field);
            LEDFlashPattern v = (LEDFlashPattern) field.get(data);
            p.setValue(v.getFlashPattern());
            parameter = p;

        } else if (type == IntensityValue.class) {

            final IntensityValue originalValue = (IntensityValue) field.get(data);

            parameter = new IntensityValueParameter(annotation.displayName(), annotation.required(), field,
                    originalValue);

        } else if (type == PositionalVariableFunction.class) {

            final PositionalVariableFunction originalFunction = (PositionalVariableFunction) field.get(data);

            parameter = new PositionalVariableFunctionParameter(annotation.displayName(), annotation.required(),
                    field, originalFunction);

        } else if ((type == SingleVariableFunction.class) || (type == KinematicVariableFunction.class)
                || (type == BehaviorLimitedKinematicVariableFunction.class)) {

            final SingleVariableFunction originalFunction = (SingleVariableFunction) field.get(data);

            parameter = new SingleVariableFunctionParameter(annotation.displayName(), annotation.required(), field,
                    originalFunction, annotation.inputUnits(), getBigDecimalValue(annotation.minimum()),
                    getBigDecimalValue(annotation.maximum()), annotation.outputUnits(),
                    getBigDecimalValue(annotation.minimumOutput()), getBigDecimalValue(annotation.maximumOutput()));

        } else if (type == BehaviorLimitedKinematicVariableFunctionList.class) {

            final BehaviorLimitedKinematicVariableFunctionList originalList = (BehaviorLimitedKinematicVariableFunctionList) field
                    .get(data);

            parameter = new BehaviorLimitedKinematicVariableFunctionListParameter(annotation.displayName(),
                    annotation.required(), field, annotation.listItemBaseName(), originalList);
        }

        if (parameter != null) {
            parameterList.add(parameter);
        }
    }

    public static BigDecimal getBigDecimalValue(String valueString) {
        BigDecimal value = null;
        if ((valueString != null) && (valueString.length() > 0)) {
            value = new BigDecimal(valueString);
        }
        return value;
    }

    public static Long getLongValue(String valueString) {
        Long value = null;
        if ((valueString != null) && (valueString.length() > 0)) {
            value = new Long(valueString);
        }
        return value;
    }

    private class SortableAnnotationField implements Comparable<SortableAnnotationField> {

        public VenkmanParameter annotation;
        public Field field;

        private SortableAnnotationField(VenkmanParameter annotation, Field field) {
            this.annotation = annotation;
            this.field = field;
        }

        @SuppressWarnings("NullableProblems")
        @Override
        public int compareTo(SortableAnnotationField o) {
            return annotation.displayOrder() - o.annotation.displayOrder();
        }
    }
}