/* * Copyright (c) 2009 The Jackson Laboratory * * This software was developed by Gary Churchill's Lab at The Jackson * Laboratory (see http://research.jax.org/faculty/churchill). * * This 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 3 of the License, or * (at your option) any later version. * * This software 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 software. If not, see <http://www.gnu.org/licenses/>. */ package org.jax.qtl.scan.gui; import java.awt.CardLayout; import java.util.logging.Logger; import javax.swing.JDialog; import javax.swing.JOptionPane; import org.jax.qtl.cross.Cross; import org.jax.qtl.scan.PhenotypeDistribution; import org.jax.qtl.scan.ScanCommandBuilder; import org.jax.qtl.scan.ScanType; import org.jax.r.gui.RCommandEditorListener; import org.jax.util.TextWrapper; /** * The all scan panel breaks the scan functionality across a couple of panels * that we can toggle between using the {@link AllScanPanels#next()} * and {@link AllScanPanels#back()} functions. There's also a * {@link AllScanPanels#validateData()} function that should be used to make * sure that the data is valid before we "commit" the scan command. * @author <A HREF="mailto:keith.sheppard@jax.org">Keith Sheppard</A> */ public class AllScanPanels extends ScanCommandEditorPanel { /** * our logger */ private static final Logger LOG = Logger.getLogger( AllScanPanels.class.getName()); /** * every {@link java.io.Serializable} is supposed to have this */ private static final long serialVersionUID = -1286763458908518025L; /** * Enumeration for the different possible inner panels that this * "all" panel can show */ private static enum InnerPanel { /** * */ CROSS_AND_CHROMOSOME, /** * */ COVARIATES, /** * */ SCAN_METHOD_AND_PARAMETERS, /** * */ PERMUTATIONS_AND_RESULTS } private volatile InnerPanel currentInnerPanel; private final ScanCommandBuilder scanCommand; private final CrossAndPhenotypesScanPanel crossAndPhenotypesScanPanel; private final ChromosomesAndCovariatesPanel chromosomesAndCovariatesPanel; private final ScanMethodAndParametersScanPanel scanMethodAndParametersScanPanel; private final PermutationsAndResultScanPanel permutationsAndResultScanPanel; /** * Constructor * @param parentDialog * the parent frame we can use to show dialogs * @param scanCommand * the scan command that we're editing * @param availableCrosses * the crosses that we can select from * @param selectedCross * the default selection */ public AllScanPanels( JDialog parentDialog, ScanCommandBuilder scanCommand, Cross[] availableCrosses, Cross selectedCross) { this.scanCommand = scanCommand; this.crossAndPhenotypesScanPanel = new CrossAndPhenotypesScanPanel( parentDialog, scanCommand, availableCrosses, selectedCross); this.chromosomesAndCovariatesPanel = new ChromosomesAndCovariatesPanel( scanCommand); this.scanMethodAndParametersScanPanel = new ScanMethodAndParametersScanPanel( parentDialog, scanCommand); this.permutationsAndResultScanPanel = new PermutationsAndResultScanPanel( scanCommand); this.initComponents(); this.postGuiInit(); } /** * {@inheritDoc} */ @Override public void addRCommandEditorListener(RCommandEditorListener editorListener) { this.crossAndPhenotypesScanPanel.addRCommandEditorListener(editorListener); this.chromosomesAndCovariatesPanel.addRCommandEditorListener(editorListener); this.scanMethodAndParametersScanPanel.addRCommandEditorListener(editorListener); this.permutationsAndResultScanPanel.addRCommandEditorListener(editorListener); } /** * {@inheritDoc} */ @Override public void removeRCommandEditorListener( RCommandEditorListener editorListener) { this.crossAndPhenotypesScanPanel.removeRCommandEditorListener(editorListener); this.chromosomesAndCovariatesPanel.removeRCommandEditorListener(editorListener); this.scanMethodAndParametersScanPanel.removeRCommandEditorListener(editorListener); this.permutationsAndResultScanPanel.removeRCommandEditorListener(editorListener); } /** * Handle the initialization that isn't taken care of by the GUI * builder */ private void postGuiInit() { // do some of the post GUI initialization this.add( this.crossAndPhenotypesScanPanel, InnerPanel.CROSS_AND_CHROMOSOME.name()); this.add( this.chromosomesAndCovariatesPanel, InnerPanel.COVARIATES.name()); this.add( this.scanMethodAndParametersScanPanel, InnerPanel.SCAN_METHOD_AND_PARAMETERS.name()); this.add( this.permutationsAndResultScanPanel, InnerPanel.PERMUTATIONS_AND_RESULTS.name()); this.setCurrentInnerPanel(InnerPanel.CROSS_AND_CHROMOSOME); } /** * Change the current inner panel to the given value. * @param currentInnerPanel * the new value for the current inner panel */ private void setCurrentInnerPanel(InnerPanel currentInnerPanel) { this.currentInnerPanel = currentInnerPanel; this.getLayout().show(this, currentInnerPanel.name()); } /** * go to the next panel * @see #next() */ public void next() { switch(this.currentInnerPanel) { case CROSS_AND_CHROMOSOME: { if(this.crossAndPhenotypesScanPanel.validateData()) { this.chromosomesAndCovariatesPanel.refreshGui(); this.setCurrentInnerPanel(InnerPanel.COVARIATES); } } break; case COVARIATES: { if(this.chromosomesAndCovariatesPanel.validateData()) { this.scanMethodAndParametersScanPanel.refreshGui(); this.setCurrentInnerPanel(InnerPanel.SCAN_METHOD_AND_PARAMETERS); if(this.scanCommand.getPhenotypeDistribution() == PhenotypeDistribution.OTHER && this.scanCommand.getScanType() == ScanType.SCANONE) { // skip over scan method for "other" distribution this.next(); } } } break; case SCAN_METHOD_AND_PARAMETERS: { if(this.scanMethodAndParametersScanPanel.validateData()) { this.permutationsAndResultScanPanel.refreshGui(); this.setCurrentInnerPanel(InnerPanel.PERMUTATIONS_AND_RESULTS); } } break; case PERMUTATIONS_AND_RESULTS: { throw new IllegalStateException( "cannot call next when the permutations and results " + "panel is active"); } default: { // we should never reach this throw new IllegalStateException( "unrecognized inner panel type: " + this.currentInnerPanel.name()); } } } /** * Determine if it is valid to invoke {@link #next()} * @return * true iff it is valid */ public boolean isNextValid() { return this.currentInnerPanel != InnerPanel.PERMUTATIONS_AND_RESULTS; } /** * Determine if it is valid to invoke {@link #back()} * @return * true iff it is valid */ public boolean isBackValid() { return this.currentInnerPanel != InnerPanel.CROSS_AND_CHROMOSOME; } /** * Determine if we're at the last panel and a "finish" is valid. * @return * true iff it is valid */ public boolean isFinishValid() { return this.currentInnerPanel == InnerPanel.PERMUTATIONS_AND_RESULTS; } /** * go back one panel * @see #isBackValid() */ public void back() { switch(this.currentInnerPanel) { case CROSS_AND_CHROMOSOME: { throw new IllegalStateException( "cannot call back when the cross & chromosome " + "panel is active"); } case COVARIATES: { this.setCurrentInnerPanel(InnerPanel.CROSS_AND_CHROMOSOME); } break; case SCAN_METHOD_AND_PARAMETERS: { this.setCurrentInnerPanel(InnerPanel.COVARIATES); } break; case PERMUTATIONS_AND_RESULTS: { this.setCurrentInnerPanel(InnerPanel.SCAN_METHOD_AND_PARAMETERS); if(this.scanCommand.getPhenotypeDistribution() == PhenotypeDistribution.OTHER && this.scanCommand.getScanType() == ScanType.SCANONE) { // skip over scan method for "other" distribution this.back(); } } break; default: { // we should never reach this throw new IllegalStateException( "unrecognized inner panel type: " + this.currentInnerPanel.name()); } } } /** * start the help for the current panel */ public void help() { // TODO fill in help } /** * This function just casts the result of * {@link javax.swing.JPanel#getLayout()} to a * {@link java.awt.CardLayout}. * @return * the {@link java.awt.CardLayout} */ @Override public CardLayout getLayout() { return (CardLayout)super.getLayout(); } /** * This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ @SuppressWarnings("all") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { setLayout(new java.awt.CardLayout()); }// </editor-fold>//GEN-END:initComponents /** * Validate the data contained in the panels. The user is alerted if * there is something wrong with the data format * @return * true iff the validation succeeds */ public boolean validateData() { // first go through a "GUI" level validation. this should catch every // problem, but just in case it does not, we should to a final // command level validation since this is the final validation that // this command will go through boolean guiValid = this.crossAndPhenotypesScanPanel.validateData() && this.scanMethodAndParametersScanPanel.validateData() && this.permutationsAndResultScanPanel.validateData(); if(!guiValid) { return false; } else { String message = this.scanCommand.getInvalidAssignmentCommandMessage(); if(message != null) { LOG.severe( "received a command error message that we were " + "not able to catch during GUI validation: " + message); JOptionPane.showMessageDialog( this, TextWrapper.wrapText( message, TextWrapper.DEFAULT_DIALOG_COLUMN_COUNT), "Validation Failed", JOptionPane.WARNING_MESSAGE); return false; } else { return true; } } } /** * {@inheritDoc} */ @Override protected ScanCommandBuilder getScanCommand() { return this.scanCommand; } // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables }