org.generationcp.breeding.manager.crossingmanager.AdditionalDetailsCrossNameComponent.java Source code

Java tutorial

Introduction

Here is the source code for org.generationcp.breeding.manager.crossingmanager.AdditionalDetailsCrossNameComponent.java

Source

/*******************************************************************************
 * Copyright (c) 2012, All Rights Reserved.
 * 
 * Generation Challenge Programme (GCP)
 * 
 * 
 * This software is licensed for use under the terms of the GNU General Public
 * License (http://bit.ly/8Ztv8M) and the provisions of Part F of the Generation
 * Challenge Programme Amended Consortium Agreement (http://bit.ly/KQX1nL)
 * 
 *******************************************************************************/

package org.generationcp.breeding.manager.crossingmanager;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.generationcp.breeding.manager.application.Message;
import org.generationcp.breeding.manager.crossingmanager.listeners.CrossingManagerImportButtonClickListener;
import org.generationcp.breeding.manager.crossingmanager.pojos.GermplasmListEntry;
import org.generationcp.commons.vaadin.spring.InternationalizableComponent;
import org.generationcp.commons.vaadin.spring.SimpleResourceBundleMessageSource;
import org.generationcp.commons.vaadin.util.MessageNotifier;
import org.generationcp.middleware.exceptions.MiddlewareQueryException;
import org.generationcp.middleware.manager.api.GermplasmDataManager;
import org.generationcp.middleware.pojos.Germplasm;
import org.generationcp.middleware.pojos.Name;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;

import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.ui.AbsoluteLayout;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.Button;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.Label;
import com.vaadin.ui.OptionGroup;
import com.vaadin.ui.Select;
import com.vaadin.ui.TextField;
import com.vaadin.ui.Window;
import com.vaadin.ui.Window.Notification;

/**
 * This class contains the absolute layout of UI elements in Cross Name section
 * in "Enter Additional Details..." tab in Crossing Manager application
 * 
 * @author Darla Ani
 *
 */
@Configurable
public class AdditionalDetailsCrossNameComponent extends AbsoluteLayout
        implements InitializingBean, InternationalizableComponent, CrossesMadeContainerUpdateListener {

    public static final String GENERATE_BUTTON_ID = "Generate Next Name Id";

    private static final long serialVersionUID = -1197900610042529900L;
    private static final Logger LOG = LoggerFactory.getLogger(AdditionalDetailsCrossNameComponent.class);
    private static final Integer MAX_LEADING_ZEROS = 10;

    @Autowired
    private SimpleResourceBundleMessageSource messageSource;

    @Autowired
    private GermplasmDataManager germplasmManager;

    private Label specifyPrefixLabel;
    private Label specifySuffixLabel;
    private Label howManyDigitsLabel;
    private Label nextNameInSequenceLabel;
    private Label generatedNameLabel;

    private OptionGroup crossNameOptionGroup;
    private TextField prefixTextField;
    private TextField suffixTextField;
    private CheckBox sequenceNumCheckBox;
    private Select leadingZerosSelect;
    private Button generateButton;

    private AbstractComponent[] digitsToggableComponents = new AbstractComponent[2];
    private AbstractComponent[] otherToggableComponents = new AbstractComponent[8];

    private String lastPrefixUsed; //store prefix used for MW method including zeros, if any
    private Integer nextNumberInSequence;

    private CrossesMadeContainer container;

    @Override
    public void setCrossesMadeContainer(CrossesMadeContainer container) {
        this.container = container;
    }

    @SuppressWarnings("serial")
    @Override
    public void afterPropertiesSet() throws Exception {
        setHeight("200px");
        setWidth("700px");

        crossNameOptionGroup = new OptionGroup();
        sequenceNumCheckBox = new CheckBox();
        sequenceNumCheckBox.setImmediate(true);
        sequenceNumCheckBox.addListener(new Property.ValueChangeListener() {
            @Override
            public void valueChange(ValueChangeEvent event) {
                enableSpecifyLeadingZerosComponents(sequenceNumCheckBox.booleanValue());
            }
        });

        specifyPrefixLabel = new Label();
        prefixTextField = new TextField();
        prefixTextField.setWidth("500px");

        howManyDigitsLabel = new Label();
        leadingZerosSelect = new Select();
        for (int i = 1; i <= MAX_LEADING_ZEROS; i++) {
            leadingZerosSelect.addItem(Integer.valueOf(i));
        }
        leadingZerosSelect.setNullSelectionAllowed(false);
        leadingZerosSelect.select(Integer.valueOf(1));
        leadingZerosSelect.setWidth("50px");

        specifySuffixLabel = new Label();
        suffixTextField = new TextField();
        suffixTextField.setWidth("500px");

        nextNameInSequenceLabel = new Label();
        generatedNameLabel = new Label();

        generateButton = new Button();
        generateButton.setData(GENERATE_BUTTON_ID);
        generateButton.addListener(new CrossingManagerImportButtonClickListener(this));

        layoutComponents();
        initializeToggableComponents();
    }

    @Override
    public void attach() {
        super.attach();
        updateLabels();
    }

    @Override
    public void updateLabels() {
        messageSource.setCaption(specifyPrefixLabel, Message.SPECIFY_PREFIX_REQUIRED);
        messageSource.setCaption(specifySuffixLabel, Message.SPECIFY_SUFFIX_OPTIONAL);
        messageSource.setCaption(sequenceNumCheckBox, Message.SEQUENCE_NUMBER_SHOULD_HAVE_LEADING_ZEROS);
        messageSource.setCaption(howManyDigitsLabel, Message.HOW_MANY_DIGITS);
        messageSource.setCaption(nextNameInSequenceLabel, Message.THE_NEXT_NAME_IN_THE_SEQUENCE_WILL_BE);
        messageSource.setCaption(generateButton, Message.GENERATE);
    }

    private void layoutComponents() {
        addComponent(crossNameOptionGroup, "top:10px;left:20px");
        addComponent(specifyPrefixLabel, "top:40px;left:20px");
        addComponent(prefixTextField, "top:25px;left:180px");
        addComponent(sequenceNumCheckBox, "top:57px;left:20px");
        addComponent(howManyDigitsLabel, "top:73px;left:400px");
        addComponent(leadingZerosSelect, "top:55px;left:520px");
        addComponent(specifySuffixLabel, "top:110px;left:20px");
        addComponent(suffixTextField, "top:90px;left:180px");
        addComponent(nextNameInSequenceLabel, "top:145px;left:20px");
        addComponent(generatedNameLabel, "top:145px;left:237px");
        addComponent(generateButton, "top:155px;left:20px");
    }

    private void initializeToggableComponents() {
        digitsToggableComponents[0] = howManyDigitsLabel;
        digitsToggableComponents[1] = leadingZerosSelect;

        otherToggableComponents[0] = specifyPrefixLabel;
        otherToggableComponents[1] = specifySuffixLabel;
        otherToggableComponents[2] = nextNameInSequenceLabel;
        otherToggableComponents[3] = prefixTextField;
        otherToggableComponents[4] = suffixTextField;
        otherToggableComponents[5] = sequenceNumCheckBox;
        otherToggableComponents[6] = generatedNameLabel;
        otherToggableComponents[7] = generateButton;

        enableSpecifyCrossNameComponents(true);
    }

    // Enables / disables UI elements for specifying Cross Name details
    private void enableSpecifyCrossNameComponents(boolean enabled) {
        for (AbstractComponent component : otherToggableComponents) {
            component.setEnabled(enabled);
        }
        enableSpecifyLeadingZerosComponents(enabled && sequenceNumCheckBox.booleanValue());
    }

    private void enableSpecifyLeadingZerosComponents(boolean enabled) {
        for (AbstractComponent component : digitsToggableComponents) {
            component.setEnabled(enabled);
        }
    }

    // Action handler for Generation button
    public void generateNextNameButtonAction() {
        if (validateCrossNameFields()) {
            String suffix = ((String) suffixTextField.getValue()).trim();

            try {
                lastPrefixUsed = buildPrefixString();
                String nextSequenceNumberString = this.germplasmManager
                        .getNextSequenceNumberForCrossName(lastPrefixUsed);

                nextNumberInSequence = Integer.parseInt(nextSequenceNumberString);
                generatedNameLabel
                        .setCaption(buildNextNameInSequence(lastPrefixUsed, suffix, nextNumberInSequence));

            } catch (MiddlewareQueryException e) {
                LOG.error(e.toString() + "\n" + e.getStackTrace());
                e.printStackTrace();
                MessageNotifier.showError(getWindow(), messageSource.getMessage(Message.ERROR_DATABASE),
                        messageSource.getMessage(Message.ERROR_IN_GETTING_NEXT_NUMBER_IN_CROSS_NAME_SEQUENCE),
                        Notification.POSITION_CENTERED);
            }
        }

    }

    private boolean validateCrossNameFields() {
        Window window = getWindow();
        String prefix = ((String) prefixTextField.getValue()).trim();

        if (StringUtils.isEmpty(prefix)) {
            MessageNotifier.showError(window, "Error with Cross Code",
                    messageSource.getMessage(Message.ERROR_ENTER_PREFIX_FIRST), Notification.POSITION_CENTERED);
            return false;

        } else if (prefix.contains(" ")) {
            MessageNotifier.showError(window, "Error with Cross Code",
                    messageSource.getMessage(Message.ERROR_PREFIX_HAS_WHITESPACE), Notification.POSITION_CENTERED);
            return false;
        }

        return true;
    }

    private boolean validateGeneratedName() {

        // if Generate button never pressed
        if (nextNumberInSequence == null) {
            MessageNotifier.showError(
                    getWindow(), "Error with Cross Code", MessageFormat
                            .format(messageSource.getMessage(Message.ERROR_NEXT_NAME_MUST_BE_GENERATED_FIRST), ""),
                    Notification.POSITION_CENTERED);
            return false;

            // if prefix specifications were changed and next name in sequence not generated first
        } else {
            String currentPrefixString = buildPrefixString();
            if (!currentPrefixString.equals(lastPrefixUsed)) {
                MessageNotifier.showError(getWindow(), "Error with Cross Code",
                        MessageFormat.format(
                                messageSource.getMessage(Message.ERROR_NEXT_NAME_MUST_BE_GENERATED_FIRST),
                                " (" + currentPrefixString + ")"),
                        Notification.POSITION_CENTERED);
                return false;
            }
        }

        return true;
    }

    private String buildPrefixString() {
        return ((String) prefixTextField.getValue()).trim() + " ";
    }

    private String buildNextNameInSequence(String prefix, String suffix, Integer number) {
        StringBuilder sb = new StringBuilder();
        sb.append(prefix);
        sb.append(getNumberWithLeadingZeroesAsString(number));
        if (!StringUtils.isEmpty(suffix)) {
            sb.append(" ");
            sb.append(suffix);
        }
        return sb.toString();
    }

    private String getNumberWithLeadingZeroesAsString(Integer number) {
        StringBuilder sb = new StringBuilder();
        String numberString = number.toString();
        if (sequenceNumCheckBox.booleanValue()) {
            Integer numOfZeros = (Integer) leadingZerosSelect.getValue();
            int numOfZerosNeeded = numOfZeros - numberString.length();
            if (numOfZerosNeeded > 0) {
                for (int i = 0; i < numOfZerosNeeded; i++) {
                    sb.append("0");
                }
            }
        }
        sb.append(number);
        return sb.toString();
    }

    @Override
    public boolean updateCrossesMadeContainer() {

        if (this.container != null && this.container.getCrossesMade() != null
                && this.container.getCrossesMade().getCrossesMap() != null && validateCrossNameFields()
                && validateGeneratedName()) {

            int ctr = nextNumberInSequence;
            String suffix = (String) suffixTextField.getValue();

            Map<Germplasm, Name> crossesMap = this.container.getCrossesMade().getCrossesMap();
            List<GermplasmListEntry> oldCrossNames = new ArrayList<GermplasmListEntry>();

            // Store old cross name and generate new names based on prefix, suffix specifications
            for (Map.Entry<Germplasm, Name> entry : crossesMap.entrySet()) {
                Name nameObject = entry.getValue();
                String oldCrossName = nameObject.getNval();
                nameObject.setNval(buildNextNameInSequence(lastPrefixUsed, suffix, ctr++));

                Germplasm germplasm = entry.getKey();
                Integer tempGid = germplasm.getGid();
                GermplasmListEntry oldNameEntry = new GermplasmListEntry(tempGid, tempGid, tempGid, oldCrossName);

                oldCrossNames.add(oldNameEntry);
            }
            // Only store the "original" cross names, would not store previous names on 2nd, 3rd, ... change
            if (this.container.getCrossesMade().getOldCrossNames() == null
                    || this.container.getCrossesMade().getOldCrossNames().isEmpty()) {
                this.container.getCrossesMade().setOldCrossNames(oldCrossNames);
            }

            return true;

        }

        return false;
    }

}