com.anrisoftware.prefdialog.fields.spinner.SpinnerField.java Source code

Java tutorial

Introduction

Here is the source code for com.anrisoftware.prefdialog.fields.spinner.SpinnerField.java

Source

/*
 * Copyright 2013-2016 Erwin Mller <erwin.mueller@deventm.org>
 *
 * This file is part of prefdialog-corefields.
 *
 * prefdialog-corefields is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 *
 * prefdialog-corefields is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with prefdialog-corefields. If not, see <http://www.gnu.org/licenses/>.
 */
package com.anrisoftware.prefdialog.fields.spinner;

import static org.apache.commons.lang3.StringUtils.isBlank;

import java.beans.PropertyVetoException;
import java.lang.annotation.Annotation;
import java.util.Date;
import java.util.List;

import javax.inject.Inject;
import javax.swing.JSpinner;
import javax.swing.SpinnerDateModel;
import javax.swing.SpinnerListModel;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import com.anrisoftware.globalpom.reflection.annotationclass.AnnotationClass;
import com.anrisoftware.globalpom.reflection.annotationclass.AnnotationClassFactory;
import com.anrisoftware.globalpom.reflection.annotations.AnnotationAccess;
import com.anrisoftware.globalpom.reflection.annotations.AnnotationAccessFactory;
import com.anrisoftware.globalpom.reflection.beans.BeanAccessFactory;
import com.anrisoftware.prefdialog.annotations.Spinner;
import com.anrisoftware.prefdialog.core.AbstractTitleField;
import com.anrisoftware.prefdialog.fields.spacer.Spacer;
import com.google.inject.assistedinject.Assisted;

/**
 * Sets the properties of the spinner field.
 * 
 * @see Spacer
 * 
 * @author Erwin Mueller, erwin.mueller@deventm.org
 * @since 3.0
 */
@SuppressWarnings("serial")
public class SpinnerField extends AbstractTitleField<JSpinner> {

    private static final String STEP_SIZE_ATTRIBUTE = "stepSize";

    private static final String MINIMUM_ATTRIBUTE = "minimum";

    private static final String MAXIMUM_ATTRIBUTE = "maximum";

    private static final Class<? extends Annotation> ANNOTATION_CLASS = Spinner.class;

    private static final String MODEL_ELEMENT = "model";

    private static final String START_ATTRIBUTE = "start";

    private static final String END_ATTRIBUTE = "end";

    private static final String CALENDAR_FIELD_ATTRIBUTE = "calendarField";

    private final SpinnerFieldLogger log;

    private final ChangeListener changeListener;

    private transient AnnotationClassFactory annotationClassFactory;

    private transient AnnotationAccess annotationAccess;

    private transient BeanAccessFactory beanAccessFactory;

    private boolean customModelSet;

    /**
     * @see SpinnerFieldFactory#create(Object, String)
     */
    @Inject
    SpinnerField(SpinnerFieldLogger logger, @Assisted Object parentObject, @Assisted String fieldName) {
        super(new JSpinner(), parentObject, fieldName);
        this.log = logger;
        this.customModelSet = false;
        this.changeListener = new ChangeListener() {

            @Override
            public void stateChanged(ChangeEvent e) {
                try {
                    setValue(getComponent().getValue());
                } catch (PropertyVetoException e1) {
                }
            }
        };

    }

    @Inject
    void setupSpinnerField(AnnotationClassFactory annotationClassFactory,
            AnnotationAccessFactory annotationAccessFactory, BeanAccessFactory beanAccessFactory) {
        this.annotationClassFactory = annotationClassFactory;
        this.annotationAccess = annotationAccessFactory.create(ANNOTATION_CLASS, getAccessibleObject());
        this.beanAccessFactory = beanAccessFactory;
        SpinnerModel defaultModel = createDefaultModel();
        setupModel(defaultModel);
        getComponent().setValue(getValue());
    }

    private void setupModel(SpinnerModel defaultModel) {
        @SuppressWarnings("unchecked")
        AnnotationClass<SpinnerModel> annotationClass = (AnnotationClass<SpinnerModel>) annotationClassFactory
                .create(getParentObject(), ANNOTATION_CLASS, getAccessibleObject());
        SpinnerModel model = annotationClass.withDefault(defaultModel).forAttribute(MODEL_ELEMENT).build();
        setModel(model);
    }

    private SpinnerModel createDefaultModel() {
        SpinnerModel model = createNumberModel();
        model = model == null ? createDateModel() : model;
        model = model == null ? createListModel() : model;
        model = model == null ? new SpinnerNumberModel() : model;
        return model;
    }

    private SpinnerModel createListModel() {
        String field = annotationAccess.getValue("elements");
        if (isBlank(field)) {
            return null;
        }
        return new SpinnerListModel(beanAccessFactory.create(field, getParentObject()).<List<?>>getValue());
    }

    private SpinnerModel createDateModel() {
        Object value = getValue();
        if (!(value instanceof Date)) {
            return null;
        }
        long[] start = annotationAccess.getValue(START_ATTRIBUTE);
        long[] end = annotationAccess.getValue(END_ATTRIBUTE);
        int field = annotationAccess.getValue(CALENDAR_FIELD_ATTRIBUTE);
        Comparable<?> cstart = start.length == 0 ? null : new Date(start[0]);
        Comparable<?> cend = end.length == 0 ? null : new Date(end[0]);
        return new SpinnerDateModel((Date) value, cstart, cend, field);
    }

    private SpinnerModel createNumberModel() {
        Object value = getValue();
        if (!(value instanceof Number)) {
            return null;
        }
        double[] max = annotationAccess.getValue(MAXIMUM_ATTRIBUTE);
        double[] min = annotationAccess.getValue(MINIMUM_ATTRIBUTE);
        double size = annotationAccess.getValue(STEP_SIZE_ATTRIBUTE);
        if (value instanceof Integer) {
            Comparable<?> maximum = max.length == 0 ? null : (int) max[0];
            Comparable<?> minimum = min.length == 0 ? null : (int) min[0];
            return new SpinnerNumberModel((Number) getValue(), minimum, maximum, (int) size);
        }
        if (value instanceof Long) {
            Comparable<?> maximum = max.length == 0 ? null : (long) max[0];
            Comparable<?> minimum = min.length == 0 ? null : (long) min[0];
            return new SpinnerNumberModel((Number) getValue(), minimum, maximum, (long) size);
        }
        if (value instanceof Double) {
            Comparable<?> maximum = max.length == 0 ? null : max[0];
            Comparable<?> minimum = min.length == 0 ? null : min[0];
            return new SpinnerNumberModel((Number) getValue(), minimum, maximum, size);
        }
        return null;
    }

    @Override
    public void setValue(Object value) throws PropertyVetoException {
        super.setValue(value);
        if (customModelSet) {
            getComponent().setValue(value);
        }
    }

    /**
     * Sets the spinner model for the field.
     * 
     * @param model
     *            the {@link SpinnerModel}.
     * 
     * @throws NullPointerException
     *             if the specified model is {@code null}.
     */
    public void setModel(SpinnerModel model) {
        log.checkModel(this, model);
        removeOldModel();
        getComponent().setModel(model);
        model.addChangeListener(changeListener);
        customModelSet = true;
        log.modelSet(this, model);
    }

    private void removeOldModel() {
        getComponent().getModel().removeChangeListener(changeListener);
    }

    /**
     * Sets the spinner model for the field.
     * 
     * @return the {@link SpinnerModel}.
     */
    public SpinnerModel getModel() {
        return getComponent().getModel();
    }
}