edu.ucdenver.bios.glimmpseweb.client.guided.GaussianCovariateCovariancePanel.java Source code

Java tutorial

Introduction

Here is the source code for edu.ucdenver.bios.glimmpseweb.client.guided.GaussianCovariateCovariancePanel.java

Source

/*
 * User Interface for the GLIMMPSE Software System.  Processes
 * incoming HTTP requests for power, sample size, and detectable
 * difference
 * 
 * Copyright (C) 2011 Regents of the University of Colorado.  
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package edu.ucdenver.bios.glimmpseweb.client.guided;

import java.util.List;

import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

import edu.ucdenver.bios.glimmpseweb.client.GlimmpseConstants;
import edu.ucdenver.bios.glimmpseweb.client.GlimmpseWeb;
import edu.ucdenver.bios.glimmpseweb.client.TextValidation;
import edu.ucdenver.bios.glimmpseweb.client.shared.RowColumnTextBox;
import edu.ucdenver.bios.glimmpseweb.client.wizard.WizardContext;
import edu.ucdenver.bios.glimmpseweb.client.wizard.WizardContextChangeEvent;
import edu.ucdenver.bios.glimmpseweb.client.wizard.WizardStepPanel;
import edu.ucdenver.bios.glimmpseweb.client.wizard.WizardStepPanelState;
import edu.ucdenver.bios.glimmpseweb.context.StudyDesignChangeEvent;
import edu.ucdenver.bios.glimmpseweb.context.StudyDesignContext;
import edu.ucdenver.bios.webservice.common.domain.NamedMatrix;
import edu.ucdenver.bios.webservice.common.domain.RepeatedMeasuresNode;
import edu.ucdenver.bios.webservice.common.domain.ResponseNode;
import edu.ucdenver.bios.webservice.common.domain.Spacing;

/**
 * Screen to input the correlation between the gaussian covariate
 * and the outcomes.
 * @author VIJAY AKULA
 * @author Sarah Kreidler
 *
 */
public class GaussianCovariateCovariancePanel extends WizardStepPanel implements ChangeHandler {
    // context object
    protected StudyDesignContext studyDesignContext;

    // column indices for repeated measures dropdown lists
    protected static final int LABEL_COLUMN = 0;
    protected static final int LISTBOX_COLUMN = 1;
    // flextable index for correlation textboxes
    protected static final int TEXTBOX_COLUMN = 1;

    // complete matrix data for covariance of outcomes and Gaussian covariate
    protected int currentRowOffset = 0;

    // standard deviation of Gaussian covariate
    protected TextBox standardDeviationTextBox = new TextBox();
    // flex table representing sigma YG
    protected FlexTable sigmaYGTable = new FlexTable();
    // table headers
    protected HTML outcomesHTML = new HTML(GlimmpseWeb.constants.randomCovariateCovarianceOutcomesColumnLabel());
    protected HTML correlationHTML = new HTML(
            GlimmpseWeb.constants.randomCovariateCovarianceCorrelationColumnLabel());
    // selection of repeated measures
    protected VerticalPanel rmPanel = new VerticalPanel();
    protected HTML rmInstructions = new HTML(
            GlimmpseWeb.constants.randomCovariateCovarianceRepeatedMeasuresInstructions());
    protected FlexTable repeatedMeasuresTable = new FlexTable();
    // check box to allow users to enter one correlation value and share it across all
    // repeated measures
    CheckBox sameCorrelationCheckBox = new CheckBox(
            GlimmpseWeb.constants.randomCovariateCovarianceSameCorrelationInstructions());

    // counts of responses, repeated measures
    protected boolean hasCovariate = false;

    // error message
    protected HTML stdDevErrorHTML = new HTML();
    protected HTML correlationErrorHTML = new HTML();

    /**
     * Constructor
     * @param context study design context object
     */
    public GaussianCovariateCovariancePanel(WizardContext context) {
        super(context, GlimmpseWeb.constants.navItemVariabilityGaussianCovariate(), WizardStepPanelState.SKIPPED);
        studyDesignContext = (StudyDesignContext) context;

        VerticalPanel verticalPanel = new VerticalPanel();
        // header text
        HTML header = new HTML(GlimmpseWeb.constants.randomCovariateCovarianceHeader());
        HTML description = new HTML(GlimmpseWeb.constants.randomCovariateCovarianceDescription());

        // add validation to standard deviation box
        standardDeviationTextBox.addChangeHandler(new ChangeHandler() {
            @Override
            public void onChange(ChangeEvent event) {
                TextBox tb = (TextBox) event.getSource();
                double value = 1;
                try {
                    value = TextValidation.parseDouble(tb.getValue(), 0, true);
                    TextValidation.displayOkay(stdDevErrorHTML, "");
                } catch (Exception e) {
                    TextValidation.displayError(stdDevErrorHTML,
                            GlimmpseWeb.constants.errorInvalidStandardDeviation());
                    tb.setText("1");
                }
                notifySigmaG(value);
                checkComplete();
            }
        });

        // add change handler for using the same correlation for all repeated measures
        sameCorrelationCheckBox.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                CheckBox cb = (CheckBox) event.getSource();
                if (cb.getValue()) {
                    setEqualCorrelationForRepeatedMeasures();
                } else {
                    enableUnequalCorrelationForRepeatedMeasures();
                }
            }
        });

        // layout the repeated measures panel
        rmPanel.add(rmInstructions);
        rmPanel.add(repeatedMeasuresTable);
        rmPanel.add(sameCorrelationCheckBox);
        rmPanel.setVisible(false);

        // layout the overall panel
        verticalPanel.add(header);
        verticalPanel.add(description);
        verticalPanel.add(new HTML(GlimmpseWeb.constants.randomCovariateCovarianceStandardDeviationInstructions()));
        verticalPanel.add(standardDeviationTextBox);
        verticalPanel.add(stdDevErrorHTML);
        verticalPanel.add(new HTML(GlimmpseWeb.constants.randomCovariateCovarianceCorrelationInstructions()));
        verticalPanel.add(sigmaYGTable);
        verticalPanel.add(correlationErrorHTML);
        verticalPanel.add(rmPanel);

        // add style
        verticalPanel.setStyleName(GlimmpseConstants.STYLE_WIZARD_STEP_PANEL);
        header.setStyleName(GlimmpseConstants.STYLE_WIZARD_STEP_HEADER);
        description.setStyleName(GlimmpseConstants.STYLE_WIZARD_STEP_DESCRIPTION);
        sameCorrelationCheckBox.setStyleName(GlimmpseConstants.STYLE_WIZARD_STEP_DESCRIPTION);
        sigmaYGTable.setStyleName(GlimmpseConstants.STYLE_WIZARD_STEP_TABLE);
        stdDevErrorHTML.setStyleName(GlimmpseConstants.STYLE_MESSAGE);
        correlationErrorHTML.setStyleName(GlimmpseConstants.STYLE_MESSAGE);

        initWidget(verticalPanel);

    }

    /**
     * Clear the text boxes, flex table of correlations, etc.
     */
    @Override
    public void reset() {
        hasCovariate = false;
        sigmaYGTable.removeAllRows();
        repeatedMeasuresTable.removeAllRows();
        currentRowOffset = 0;
        sameCorrelationCheckBox.setValue(false);
        changeState(WizardStepPanelState.SKIPPED);
    }

    /**
     * Copy the currently displayed values across all repeated measurements
     */
    private void setEqualCorrelationForRepeatedMeasures() {
        int totalResponseVariables = studyDesignContext.getValidResponseVariableCount();
        int totalResponses = studyDesignContext.getValidTotalResponsesCount();
        // populate the entire sigmaYG matrix with the appropriate values
        if (totalResponseVariables > 0) {
            for (int row = 0; row < totalResponses; row += totalResponseVariables) {
                if (row != currentRowOffset) {
                    for (int responseIdx = 0; responseIdx < totalResponseVariables; responseIdx++) {
                        studyDesignContext.setCovariateOutcomesCovarianceValue(this, row + responseIdx, 0,
                                studyDesignContext
                                        .getCovariateOutcomesCovarianceValue(currentRowOffset + responseIdx, 0));
                        //                                sigmaYGData[row+responseIdx][0] = sigmaYGData[currentRowOffset+responseIdx][0];
                    }
                }
            }
            // now reset the view to the first time point and disable the repeated measures drop down
            for (int i = 0; i < repeatedMeasuresTable.getRowCount(); i++) {
                ListBox lb = (ListBox) repeatedMeasuresTable.getWidget(i, LISTBOX_COLUMN);
                lb.setSelectedIndex(0);
                lb.setEnabled(false);
            }
            updateMatrixView();
        }
    }

    /**
     * Enable the repeated measures dropdown lists
     */
    private void enableUnequalCorrelationForRepeatedMeasures() {
        // reenable the repeated measures dropdowns
        for (int i = 0; i < repeatedMeasuresTable.getRowCount(); i++) {
            ListBox lb = (ListBox) repeatedMeasuresTable.getWidget(i, LISTBOX_COLUMN);
            lb.setEnabled(true);
        }
    }

    /**
     * Load the repeated measures information from the context
     */
    private void loadRepeatedMeasuresFromContext() {
        // clear the repeated measures table
        repeatedMeasuresTable.removeAllRows();
        rmPanel.setVisible(false);

        List<RepeatedMeasuresNode> rmNodeList = studyDesignContext.getStudyDesign().getRepeatedMeasuresTree();
        if (rmNodeList != null && rmNodeList.size() > 0) {
            int totalResponseVariables = studyDesignContext.getValidResponseVariableCount();
            int totalRepeatedMeasuresCombinations = 1;
            // calculate the total repeated measures combinations
            for (RepeatedMeasuresNode rmNode : rmNodeList) {
                if (rmNode.getDimension() != null && !rmNode.getDimension().isEmpty()
                        && rmNode.getNumberOfMeasurements() != null && rmNode.getNumberOfMeasurements() > 1) {
                    totalRepeatedMeasuresCombinations *= rmNode.getNumberOfMeasurements();
                }
            }
            int totalResponses = 0;
            if (totalRepeatedMeasuresCombinations > 0 && totalResponseVariables > 0) {
                totalResponses = totalResponseVariables * totalRepeatedMeasuresCombinations;
            } else if (totalRepeatedMeasuresCombinations > 0) {
                totalResponses = totalRepeatedMeasuresCombinations;
            } else {
                totalResponses = totalResponseVariables;
            }

            /* create dropdowns displaying possible values for repeated measures.
             *  The string displays the spacing value for the dimension of repeated
             *  measures and the value is the column offset corresponding to that 
             *  value
             */
            if (totalRepeatedMeasuresCombinations > 0) {
                int row = 0;
                int offset = (totalResponses > 0 ? totalResponses : 1);
                for (RepeatedMeasuresNode rmNode : rmNodeList) {
                    if (rmNode.getDimension() != null && !rmNode.getDimension().isEmpty()
                            && rmNode.getNumberOfMeasurements() != null && rmNode.getNumberOfMeasurements() > 1) {
                        offset /= rmNode.getNumberOfMeasurements();
                        // add the label
                        repeatedMeasuresTable.setWidget(row, LABEL_COLUMN, new HTML(rmNode.getDimension()));
                        // add the listbox
                        ListBox lb = new ListBox();
                        lb.addChangeHandler(new ChangeHandler() {
                            @Override
                            public void onChange(ChangeEvent event) {
                                updateMatrixView();
                            }
                        });
                        List<Spacing> spacingList = rmNode.getSpacingList();
                        if (spacingList != null) {
                            int index = 0;
                            for (Spacing spacing : spacingList) {
                                lb.addItem(Integer.toString(spacing.getValue()), Integer.toString(index * offset));
                                index++;
                            }
                        } else {
                            for (int i = 1; i <= rmNode.getNumberOfMeasurements(); i++) {
                                lb.addItem(Integer.toString(i), Integer.toString((i - 1) * offset));
                            }
                        }
                        repeatedMeasuresTable.setWidget(row, LISTBOX_COLUMN, lb);
                        row++;
                    }
                }

            }
            rmPanel.setVisible(true);
        }
        checkComplete();
    }

    /**
     * Update the correlation text boxes to display the sigma YG
     * submatrix corresponding to the currently selected 
     * repeated measures observation episode
     */
    private void updateMatrixView() {
        // calculate the new row offset
        currentRowOffset = 0;
        for (int i = 0; i < repeatedMeasuresTable.getRowCount(); i++) {
            ListBox lb = (ListBox) repeatedMeasuresTable.getWidget(i, LISTBOX_COLUMN);
            String valueStr = lb.getValue(lb.getSelectedIndex());
            int value = Integer.parseInt(valueStr);
            currentRowOffset += value;
        }

        // update the values in the textboxes
        for (int row = 1; row < sigmaYGTable.getRowCount(); row++) {
            TextBox tb = (TextBox) sigmaYGTable.getWidget(row, TEXTBOX_COLUMN);
            double value = studyDesignContext.getCovariateOutcomesCovarianceValue(row - 1 + currentRowOffset, 0);
            if (!Double.isNaN(value)) {
                tb.setText(Double.toString(value));
            }
        }
    }

    /**
     * Load the responses from the context
     */
    private void loadResponsesFromContext() {
        // clear the data from the screen
        sigmaYGTable.removeAllRows();
        // add the header widgets
        sigmaYGTable.setWidget(0, 0, outcomesHTML);
        sigmaYGTable.setWidget(0, 1, correlationHTML);
        sigmaYGTable.getRowFormatter().setStyleName(0, GlimmpseConstants.STYLE_WIZARD_STEP_TABLE_HEADER);
        // add a row for each response variable
        List<ResponseNode> outcomeList = studyDesignContext.getStudyDesign().getResponseList();
        if (outcomeList != null && outcomeList.size() > 0) {
            // load the display
            int row = 1;
            for (ResponseNode outcome : outcomeList) {
                sigmaYGTable.getRowFormatter().setStyleName(row, GlimmpseConstants.STYLE_WIZARD_STEP_TABLE_ROW);
                sigmaYGTable.setWidget(row, 0, new HTML(outcome.getName()));
                RowColumnTextBox tb = new RowColumnTextBox(row - 1, 0);
                tb.addChangeHandler(this);
                sigmaYGTable.setWidget(row, 1, tb);
                row++;
            }

            // if repeated measures are present, update the column offsets
            if (repeatedMeasuresTable.getRowCount() > 0) {
                int offset = studyDesignContext.getValidTotalResponsesCount();
                for (row = 0; row < repeatedMeasuresTable.getRowCount(); row++) {
                    ListBox lb = (ListBox) repeatedMeasuresTable.getWidget(row, LISTBOX_COLUMN);
                    offset /= lb.getItemCount();
                    for (int i = 0; i < lb.getItemCount(); i++) {
                        lb.setValue(i, Integer.toString(i * offset));
                    }
                }
            }
        }
        checkComplete();
    }

    //    /**
    //     * Store the sigma G and sigma YG covariance matrices
    //     * in the context.
    //     */
    //    public  void onExit() 
    //    {
    //        // store the 1x1 covariance for the Gaussian covariate
    //        NamedMatrix sigmaCovariate = null;
    //        if (!standardDeviationTextBox.getValue().isEmpty()) {
    //            double[][] sigmaCovariateData = new double[1][1];
    //            double value = Double.parseDouble(standardDeviationTextBox.getValue());
    //            sigmaCovariateData[0][0] = value*value;
    //
    //            sigmaCovariate = new NamedMatrix();
    //            sigmaCovariate.setColumns(1);
    //            sigmaCovariate.setRows(1);
    //            sigmaCovariate.setDataFromArray(sigmaCovariateData);
    //            sigmaCovariate.setName(GlimmpseWeb.constants.MATRIX_SIGMA_COVARIATE);
    //        }
    //        studyDesignContext.setSigmaCovariate(this, sigmaCovariate);
    //
    //        // store the px1 covariance for the Gaussian covariate with the outcomes
    //        NamedMatrix sigmaYG = null;
    //        if (sigmaYGData != null) {
    //            sigmaYG = new NamedMatrix();
    //            sigmaYG.setColumns(sigmaYGColumns);
    //            sigmaYG.setRows(sigmaYGRows);
    //            sigmaYG.setDataFromArray(sigmaYGData);
    //            sigmaYG.setName(GlimmpseConstants.MATRIX_SIGMA_OUTCOME_COVARIATE);
    //        }
    //        studyDesignContext.setSigmaOutcomesCovariate(this, sigmaYG);
    //    }

    /**
     * Load the data from the context regarding the sigmaG and sigmaYG matrices
     */
    private void loadMatricesFromContext() {
        // load the data for the sigma G matrix
        NamedMatrix sigmaGMatrix = studyDesignContext.getStudyDesign()
                .getNamedMatrix(GlimmpseConstants.MATRIX_SIGMA_COVARIATE);
        if (sigmaGMatrix != null && sigmaGMatrix.getData() != null) {
            double[][] data = sigmaGMatrix.getData().getData();
            if (data != null) {
                standardDeviationTextBox.setText(Double.toString(data[0][0]));
            }
        }

        // load the data for the sigma YG matrix
        updateMatrixView();
    }

    /**
     * Handle changes in responses and repeated measures.
     */
    @Override
    public void onWizardContextChange(WizardContextChangeEvent e) {
        switch (((StudyDesignChangeEvent) e).getType()) {
        case COVARIATE:
            hasCovariate = studyDesignContext.getStudyDesign().isGaussianCovariate();
            break;
        case RESPONSES_LIST:
            loadResponsesFromContext();
            loadMatricesFromContext();
            break;
        case REPEATED_MEASURES:
            loadRepeatedMeasuresFromContext();
            loadMatricesFromContext();
            break;
        case COVARIATE_COVARIANCE:
            if (e.getSource() != this) {
                loadMatricesFromContext();
            }
            break;
        }
        checkComplete();
    }

    /**
     * Indicates if the screen is complete
     */
    public void checkComplete() {
        if (hasCovariate) {
            if (sigmaYGTable.getRowCount() > 1) {
                if (!standardDeviationTextBox.getValue().isEmpty()
                        && studyDesignContext.covariateCovarianceIsValid()
                        && studyDesignContext.covariateOutcomesCovarianceIsValid()) {
                    changeState(WizardStepPanelState.COMPLETE);
                } else {
                    changeState(WizardStepPanelState.INCOMPLETE);
                }
            } else {
                changeState(WizardStepPanelState.NOT_ALLOWED);
            }
        } else {
            changeState(WizardStepPanelState.SKIPPED);
        }
    }

    /**
     * Load covariance data from the context
     */
    @Override
    public void onWizardContextLoad() {
        reset();
        hasCovariate = studyDesignContext.getStudyDesign().isGaussianCovariate();
        loadResponsesFromContext();
        loadRepeatedMeasuresFromContext();
        loadMatricesFromContext();
        checkComplete();
    }

    /**
     * Textbox input validation and check complete
     */
    @Override
    public void onChange(ChangeEvent event) {
        RowColumnTextBox tb = (RowColumnTextBox) event.getSource();
        double value = 0;
        try {
            value = TextValidation.parseDouble(tb.getText(), -1.0, 1.0, true);
            TextValidation.displayOkay(correlationErrorHTML, "");
        } catch (NumberFormatException nfe) {
            TextValidation.displayError(correlationErrorHTML, GlimmpseWeb.constants.errorInvalidCorrelation());
            tb.setText("0");
        }
        notifySigmaYGValue(tb.row + currentRowOffset, 0, value);
        checkComplete();
    }

    /**
     * Store the standard deviation value to the context
     * @param stdDev
     */
    private void notifySigmaG(double stdDev) {
        studyDesignContext.setGaussianCovariateStandardDeviation(this, stdDev);
    }

    /**
     * Store the sigmaYG correlation value to the context
     * @param stdDev
     */
    private void notifySigmaYGValue(int row, int column, double correlation) {
        studyDesignContext.setCovariateOutcomesCovarianceValue(this, row, column, correlation);
    }
}