/*
* 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.cross.gui;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import javax.swing.ListSelectionModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import org.jax.qtl.cross.SimulateCrossCommandBuilder;
import org.jax.qtl.cross.SimulateMapCommandBuilder;
import org.jax.qtl.cross.SimulateCrossCommandBuilder.SimulatedQtl;
import org.jax.r.RCommand;
import org.jax.r.RSyntaxException;
import org.jax.r.RUtilities;
import org.jax.r.gui.RCommandEditorPanel;
import org.jax.r.jriutilities.JRIUtilityFunctions;
import org.jax.r.jriutilities.RInterfaceFactory;
import org.jax.util.TextWrapper;
/**
* The 2nd sim cross panel
* @author <A HREF="mailto:keith.sheppard@jax.org">Keith Sheppard</A>
*/
public class SimulateCrossPanelTwo extends RCommandEditorPanel
{
/**
* every {@link java.io.Serializable} is supposed to have one of these
*/
private static final long serialVersionUID = -116189527421901875L;
/**
* our logger
*/
private static final Logger LOG = Logger.getLogger(
SimulateCrossPanelTwo.class.getName());
private final SimulateCrossCommandBuilder simulateCrossCommandBuilder;
private final SimulateMapCommandBuilder simulateMapCommandBuilder;
private final ItemListener selectedQtlChromosomeItemListener = new ItemListener()
{
public void itemStateChanged(ItemEvent e)
{
if(e.getStateChange() == ItemEvent.SELECTED)
{
SimulateCrossPanelTwo.this.updateSelectedQtl();
}
}
};
private final ChangeListener selectedQtlChangeListener = new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
SimulateCrossPanelTwo.this.updateSelectedQtl();
}
};
private final SpinnerNumberModel qtlPositionSpinnerModel =
new SpinnerNumberModel(
0.0, // value
0.0, // min
100.0, // max
1.0); // step
private final SpinnerNumberModel qtlEffect1SpinnerModel =
new SpinnerNumberModel();
private final SpinnerNumberModel qtlEffect2SpinnerModel =
new SpinnerNumberModel();
private final SpinnerNumberModel qtlEffect3SpinnerModel =
new SpinnerNumberModel();
private final DefaultTableModel qtlsTableModel = new DefaultTableModel()
{
/**
* every {@link java.io.Serializable} is supposed to have one of these
*/
private static final long serialVersionUID = 5387415854671697500L;
/**
* {@inheritDoc}
*/
@Override
public boolean isCellEditable(int row, int column)
{
return false;
}
};
/**
* Constructor
* @param simulateCrossCommandBuilder
* the simulate cross command
* @param simulateMapCommandBuilder
* the simulate map command
*/
public SimulateCrossPanelTwo(SimulateMapCommandBuilder simulateMapCommandBuilder, SimulateCrossCommandBuilder simulateCrossCommandBuilder)
{
this.simulateCrossCommandBuilder = simulateCrossCommandBuilder;
this.simulateMapCommandBuilder = simulateMapCommandBuilder;
this.initComponents();
this.postGuiInit();
}
/**
* Take care of any of the GUI initialization that isn't handled by
* the GUI builder
*/
private void postGuiInit()
{
this.simulatedCrossNameTextField.getDocument().addDocumentListener(
new DocumentListener()
{
public void changedUpdate(DocumentEvent e)
{
SimulateCrossPanelTwo.this.updateSimulatedCrossName();
}
public void insertUpdate(DocumentEvent e)
{
SimulateCrossPanelTwo.this.updateSimulatedCrossName();
}
public void removeUpdate(DocumentEvent e)
{
SimulateCrossPanelTwo.this.updateSimulatedCrossName();
}
});
this.qtlsTable.setModel(this.qtlsTableModel);
this.qtlsTable.setSelectionMode(
ListSelectionModel.SINGLE_SELECTION);
this.qtlsTable.getSelectionModel().addListSelectionListener(
new ListSelectionListener()
{
public void valueChanged(ListSelectionEvent e)
{
SimulateCrossPanelTwo.this.qtlSelectionChanged();
}
});
this.qtlPositionSpinner.setModel(this.qtlPositionSpinnerModel);
this.qtlEffect1Spinner.setModel(this.qtlEffect1SpinnerModel);
this.qtlEffect2Spinner.setModel(this.qtlEffect2SpinnerModel);
this.qtlEffect3Spinner.setModel(this.qtlEffect3SpinnerModel);
this.refreshGui();
}
/**
* Refresh the simulate cross GUI
*/
public void refreshGui()
{
switch(this.simulateCrossCommandBuilder.getCrossType())
{
case BACK_CROSS:
{
this.qtlEffect1Label.setText(
"Homozygote Effect - Heterozygote Effect:");
this.qtlEffect2Label.setVisible(false);
this.qtlEffect2Spinner.setVisible(false);
this.qtlEffect3Label.setVisible(false);
this.qtlEffect3Spinner.setVisible(false);
this.qtlEffect4Label.setVisible(false);
this.qtlsTableModel.setColumnIdentifiers(new String[] {
"Chromosome",
"Position (cM)",
"Effect"});
}
break;
case F2:
{
this.qtlEffect1Label.setText(
"Additive Effect:");
this.qtlEffect2Label.setText(
"Dominance Deviation:");
this.qtlEffect2Label.setVisible(true);
this.qtlEffect2Spinner.setVisible(true);
this.qtlEffect3Label.setVisible(false);
this.qtlEffect3Spinner.setVisible(false);
this.qtlEffect4Label.setVisible(false);
this.qtlsTableModel.setColumnIdentifiers(new String[] {
"Chromosome",
"Position (cM)",
"Additive Effect",
"Dominance Deviation"});
}
break;
case FOUR_WAY:
{
this.qtlEffect1Label.setText(
"AC Effect:");
this.qtlEffect2Label.setText(
"BC Effect:");
this.qtlEffect3Label.setText(
"AD Effect:");
this.qtlEffect4Label.setText(
"BD Effect: 0");
this.qtlEffect2Label.setVisible(true);
this.qtlEffect2Spinner.setVisible(true);
this.qtlEffect3Label.setVisible(true);
this.qtlEffect3Spinner.setVisible(true);
this.qtlEffect4Label.setVisible(true);
this.qtlsTableModel.setColumnIdentifiers(new String[] {
"Chromosome",
"Position (cM)",
"AC Effect",
"BC Effect",
"AD Effect"});
}
break;
default:
{
LOG.warning(
"Unknown cross type: " +
this.simulateCrossCommandBuilder.getCrossType());
}
break;
}
this.listenForSelectedQtlChanges(false);
this.qtlChromosomeComboBox.removeAllItems();
int chromosomeCount =
this.simulateMapCommandBuilder.getChromosomeLengths().length;
for(int i = 0; i < chromosomeCount; i++)
{
this.qtlChromosomeComboBox.addItem(
this.chromosomeNumberToChromosomeString(i + 1));
}
this.listenForSelectedQtlChanges(true);
this.qtlsTableModel.setRowCount(0);
for(SimulatedQtl simulatedQtl: this.simulateCrossCommandBuilder.getSimulatedQtls())
{
SimulatedQtlCell[] qtlRow = new SimulatedQtlCell[] {
new SimulatedQtlCell(simulatedQtl, 0),
new SimulatedQtlCell(simulatedQtl, 1),
new SimulatedQtlCell(simulatedQtl, 2),
new SimulatedQtlCell(simulatedQtl, 3),
new SimulatedQtlCell(simulatedQtl, 4)};
this.qtlsTableModel.addRow(qtlRow);
}
this.qtlSelectionChanged();
}
/**
* {@inheritDoc}
*/
public RCommand[] getCommands()
{
return new RCommand[] {this.simulateCrossCommandBuilder.getCommand()};
}
/**
* Update the cross identifier to match what the user typed into the name
* field
*/
private void updateSimulatedCrossName()
{
try
{
this.simulateCrossCommandBuilder.setCrossName(
RUtilities.fromReadableNameToRIdentifier(
this.simulatedCrossNameTextField.getText().trim()));
this.fireCommandModified();
}
catch(RSyntaxException ex)
{
LOG.log(Level.FINE,
"can't convert cross name to identifier: " +
this.simulatedCrossNameTextField.getText().trim(),
ex);
}
}
private String chromosomeNumberToChromosomeString(int chromosomeNumber)
{
int chromosomeCount = this.simulateMapCommandBuilder.getChromosomeLengths().length;
boolean xIncluded = this.simulateMapCommandBuilder.getIncludeXChromosome();
if(chromosomeNumber == chromosomeCount && xIncluded)
{
return "X";
}
else
{
return Integer.toString(chromosomeNumber);
}
}
/**
* Update the selected qtl value
*/
private void updateSelectedQtl()
{
SimulatedQtl selectedQtl = this.getSelectedQtl();
if(selectedQtl != null)
{
selectedQtl.setChromosomeNumber(
this.qtlChromosomeComboBox.getSelectedIndex() + 1);
selectedQtl.setPositionInCentimorgans(
this.qtlPositionSpinnerModel.getNumber().doubleValue());
selectedQtl.setEffectOne(
this.qtlEffect1SpinnerModel.getNumber().doubleValue());
selectedQtl.setEffectTwo(
this.qtlEffect2SpinnerModel.getNumber().doubleValue());
selectedQtl.setEffectThree(
this.qtlEffect3SpinnerModel.getNumber().doubleValue());
this.qtlsTable.repaint();
this.fireCommandModified();
}
}
/**
* Getter for the selected qtl
* @return
* the selected qtl or null if no qtls are selected
*/
private SimulatedQtl getSelectedQtl()
{
int selectedRow = this.qtlsTable.getSelectedRow();
if(selectedRow == -1)
{
return null;
}
else
{
SimulatedQtlCell simulatedQtlCell =
(SimulatedQtlCell)this.qtlsTable.getValueAt(selectedRow, 0);
return simulatedQtlCell.getSimulatedQtl();
}
}
/**
* Respond
*/
private void qtlSelectionChanged()
{
this.listenForSelectedQtlChanges(false);
SimulatedQtl selectedQtl = this.getSelectedQtl();
if(selectedQtl != null)
{
this.qtlChromosomeComboBox.setSelectedItem(
selectedQtl.getChromosomeNumber());
this.qtlPositionSpinnerModel.setValue(
selectedQtl.getPositionInCentimorgans());
this.qtlEffect1SpinnerModel.setValue(
selectedQtl.getEffectOne());
this.qtlEffect2SpinnerModel.setValue(
selectedQtl.getEffectTwo());
this.qtlEffect3SpinnerModel.setValue(
selectedQtl.getEffectThree());
}
this.qtlChromosomeLabel.setEnabled(selectedQtl != null);
this.qtlChromosomeComboBox.setEnabled(selectedQtl != null);
this.qtlPositionLabel.setEnabled(selectedQtl != null);
this.qtlPositionSpinner.setEnabled(selectedQtl != null);
this.qtlEffectsLabel.setEnabled(selectedQtl != null);
this.qtlEffect1Label.setEnabled(selectedQtl != null);
this.qtlEffect1Spinner.setEnabled(selectedQtl != null);
this.qtlEffect2Label.setEnabled(selectedQtl != null);
this.qtlEffect2Spinner.setEnabled(selectedQtl != null);
this.qtlEffect3Label.setEnabled(selectedQtl != null);
this.qtlEffect3Spinner.setEnabled(selectedQtl != null);
this.qtlEffect4Label.setEnabled(selectedQtl != null);
this.removeQtlButton.setEnabled(selectedQtl != null);
this.listenForSelectedQtlChanges(true);
}
/**
* Either start or stop listening for changes to the QTL
* @param listen
* start listening if true, stop listening otherwise
*/
private void listenForSelectedQtlChanges(boolean listen)
{
if(listen)
{
this.qtlChromosomeComboBox.addItemListener(
this.selectedQtlChromosomeItemListener);
this.qtlPositionSpinnerModel.addChangeListener(
this.selectedQtlChangeListener);
this.qtlEffect1SpinnerModel.addChangeListener(
this.selectedQtlChangeListener);
this.qtlEffect2SpinnerModel.addChangeListener(
this.selectedQtlChangeListener);
this.qtlEffect3SpinnerModel.addChangeListener(
this.selectedQtlChangeListener);
}
else
{
this.qtlChromosomeComboBox.removeItemListener(
this.selectedQtlChromosomeItemListener);
this.qtlPositionSpinnerModel.removeChangeListener(
this.selectedQtlChangeListener);
this.qtlEffect1SpinnerModel.removeChangeListener(
this.selectedQtlChangeListener);
this.qtlEffect2SpinnerModel.removeChangeListener(
this.selectedQtlChangeListener);
this.qtlEffect3SpinnerModel.removeChangeListener(
this.selectedQtlChangeListener);
}
}
/**
* Validate the data in this panel
* @return
* true iff the data is valid
*/
public boolean validateData()
{
String readableCrossName =
this.simulatedCrossNameTextField.getText().trim();
String validationErrorMessage =
RUtilities.getErrorMessageForReadableName(
readableCrossName);
if(validationErrorMessage == null)
{
if(readableCrossName.length() == 0)
{
validationErrorMessage =
"The cross name cannot be empty. See help for " +
"more detailed information.";
}
else if(JRIUtilityFunctions.isTopLevelObject(
this.simulateCrossCommandBuilder.getCrossName(),
RInterfaceFactory.getRInterfaceInstance()))
{
validationErrorMessage =
"The name \"" + readableCrossName + "\" conflicts with " +
"an existing data object. Please choose another name.";
}
else
{
// validate the QTLs
double[] chromosomeLengths =
this.simulateMapCommandBuilder.getChromosomeLengths();
SimulatedQtl[] qtls =
this.simulateCrossCommandBuilder.getSimulatedQtls();
for(int qtlIndex = 0; qtlIndex < qtls.length; qtlIndex++)
{
int chromosomeNumber = qtls[qtlIndex].getChromosomeNumber();
if(chromosomeNumber > chromosomeLengths.length)
{
validationErrorMessage =
"The QTL in row " + (qtlIndex + 1) + " of the table " +
"has an invalid chromosome (" +
this.chromosomeNumberToChromosomeString(chromosomeNumber) +
"). Please either correct this or cancel.";
break;
}
else
{
double qtlPosition = qtls[qtlIndex].getPositionInCentimorgans();
if(qtlPosition > chromosomeLengths[chromosomeNumber - 1])
{
validationErrorMessage =
"The QTL in row " + (qtlIndex + 1) + " of the table " +
"has an invalid QTL position (" +
qtlPosition + " cM). The maximum value that " +
"can be used for chromosome " +
this.chromosomeNumberToChromosomeString(chromosomeNumber) +
" is " + chromosomeLengths[chromosomeNumber - 1] +
" cM. Please either correct this or cancel.";
break;
}
}
}
}
}
if(validationErrorMessage != null)
{
JOptionPane.showMessageDialog(
this,
TextWrapper.wrapText(
validationErrorMessage,
TextWrapper.DEFAULT_DIALOG_COLUMN_COUNT),
"Validation Failed",
JOptionPane.WARNING_MESSAGE);
return false;
}
else
{
return true;
}
}
/**
* Table cell class for qtls
*/
private class SimulatedQtlCell
{
private final SimulatedQtl simulatedQtl;
private final int column;
/**
* Constructor
* @param simulatedQtl
* the simulated qtl
* @param column
* the column
*/
public SimulatedQtlCell(SimulatedQtl simulatedQtl, int column)
{
this.simulatedQtl = simulatedQtl;
this.column = column;
}
/**
* @return the simulatedQtl
*/
public SimulatedQtl getSimulatedQtl()
{
return this.simulatedQtl;
}
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
if(this.column == 0)
{
return SimulateCrossPanelTwo.this.chromosomeNumberToChromosomeString(
this.simulatedQtl.getChromosomeNumber());
}
else if(this.column == 1)
{
return Double.toString(
this.simulatedQtl.getPositionInCentimorgans());
}
else if(this.column == 2)
{
return Double.toString(
this.simulatedQtl.getEffectOne());
}
else if(this.column == 3)
{
return Double.toString(
this.simulatedQtl.getEffectTwo());
}
else if(this.column == 4)
{
return Double.toString(
this.simulatedQtl.getEffectThree());
}
else
{
LOG.severe("bad qtl column: " + this.column);
return null;
}
}
}
private void createQtl()
{
SimulatedQtl simulatedQtl = new SimulatedQtl();
SimulatedQtl[] currentQtls =
this.simulateCrossCommandBuilder.getSimulatedQtls();
SimulatedQtl[] newQtls = new SimulatedQtl[currentQtls.length + 1];
for(int i = 0; i < currentQtls.length; i++)
{
newQtls[i] = currentQtls[i];
}
newQtls[newQtls.length - 1] = simulatedQtl;
this.simulateCrossCommandBuilder.setSimulatedQtls(newQtls);
SimulatedQtlCell[] qtlRow = new SimulatedQtlCell[] {
new SimulatedQtlCell(simulatedQtl, 0),
new SimulatedQtlCell(simulatedQtl, 1),
new SimulatedQtlCell(simulatedQtl, 2),
new SimulatedQtlCell(simulatedQtl, 3),
new SimulatedQtlCell(simulatedQtl, 4)};
this.qtlsTableModel.addRow(qtlRow);
this.qtlsTable.getSelectionModel().setSelectionInterval(
newQtls.length - 1,
newQtls.length - 1);
this.fireCommandModified();
}
private void removeQtl()
{
int selectedIndex = this.qtlsTable.getSelectedRow();
if(selectedIndex != -1)
{
SimulatedQtl[] currentQtls =
this.simulateCrossCommandBuilder.getSimulatedQtls();
SimulatedQtl[] newQtls = new SimulatedQtl[currentQtls.length - 1];
for(int i = 0; i < currentQtls.length; i++)
{
if(i < selectedIndex)
{
newQtls[i] = currentQtls[i];
}
else if(i > selectedIndex)
{
newQtls[i - 1] = currentQtls[i];
}
}
this.simulateCrossCommandBuilder.setSimulatedQtls(newQtls);
this.qtlsTableModel.removeRow(selectedIndex);
this.fireCommandModified();
}
}
/**
* 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() {
javax.swing.JLabel simulatedCrossNameLabel = new javax.swing.JLabel();
simulatedCrossNameTextField = new javax.swing.JTextField();
qtlChromosomeLabel = new javax.swing.JLabel();
qtlChromosomeComboBox = new javax.swing.JComboBox();
qtlPositionLabel = new javax.swing.JLabel();
qtlPositionSpinner = new javax.swing.JSpinner();
qtlEffectsLabel = new javax.swing.JLabel();
qtlEffect1Label = new javax.swing.JLabel();
qtlEffect1Spinner = new javax.swing.JSpinner();
qtlEffect2Label = new javax.swing.JLabel();
qtlEffect2Spinner = new javax.swing.JSpinner();
qtlEffect3Label = new javax.swing.JLabel();
qtlEffect3Spinner = new javax.swing.JSpinner();
qtlEffect4Label = new javax.swing.JLabel();
javax.swing.JScrollPane qtlsScrollPane = new javax.swing.JScrollPane();
qtlsTable = new javax.swing.JTable();
newQtlButton = new javax.swing.JButton();
removeQtlButton = new javax.swing.JButton();
simulatedCrossNameLabel.setText("Simulated Cross Name:");
qtlChromosomeLabel.setText("QTL Chromosome:");
qtlPositionLabel.setText("QTL Position (cM):");
qtlEffectsLabel.setText("QTL Effects:");
qtlEffect1Label.setText("Effect 1 Label:");
qtlEffect2Label.setText("Effect 2 Label:");
qtlEffect3Label.setText("Effect 3 Label:");
qtlEffect4Label.setText("Effect 4 Label:");
qtlsScrollPane.setViewportView(qtlsTable);
newQtlButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/action/add-16x16.png"))); // NOI18N
newQtlButton.setText("New QTL");
newQtlButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
newQtlButtonActionPerformed(evt);
}
});
removeQtlButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/action/remove-16x16.png"))); // NOI18N
removeQtlButton.setText("Remove QTL");
removeQtlButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
removeQtlButtonActionPerformed(evt);
}
});
org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup()
.addContainerGap()
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(qtlsScrollPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 615, Short.MAX_VALUE)
.add(layout.createSequentialGroup()
.add(newQtlButton)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(removeQtlButton))
.add(layout.createSequentialGroup()
.add(simulatedCrossNameLabel)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(simulatedCrossNameTextField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 115, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.add(layout.createSequentialGroup()
.add(qtlChromosomeLabel)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(qtlChromosomeComboBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(qtlPositionLabel)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(qtlPositionSpinner, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 55, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.add(layout.createSequentialGroup()
.add(qtlEffect1Label)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(qtlEffect1Spinner, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 61, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(qtlEffect2Label)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(qtlEffect2Spinner, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 61, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(qtlEffect3Label)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(qtlEffect3Spinner, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 61, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(qtlEffect4Label))
.add(qtlEffectsLabel))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(simulatedCrossNameLabel)
.add(simulatedCrossNameTextField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(qtlChromosomeLabel)
.add(qtlChromosomeComboBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.add(qtlPositionLabel)
.add(qtlPositionSpinner, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(qtlEffectsLabel)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(qtlEffect1Label)
.add(qtlEffect1Spinner, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.add(qtlEffect2Label)
.add(qtlEffect2Spinner, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.add(qtlEffect3Label)
.add(qtlEffect3Spinner, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.add(qtlEffect4Label))
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(qtlsScrollPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 176, Short.MAX_VALUE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(newQtlButton)
.add(removeQtlButton))
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
private void newQtlButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newQtlButtonActionPerformed
this.createQtl();
}//GEN-LAST:event_newQtlButtonActionPerformed
private void removeQtlButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeQtlButtonActionPerformed
this.removeQtl();
}//GEN-LAST:event_removeQtlButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton newQtlButton;
private javax.swing.JComboBox qtlChromosomeComboBox;
private javax.swing.JLabel qtlChromosomeLabel;
private javax.swing.JLabel qtlEffect1Label;
private javax.swing.JSpinner qtlEffect1Spinner;
private javax.swing.JLabel qtlEffect2Label;
private javax.swing.JSpinner qtlEffect2Spinner;
private javax.swing.JLabel qtlEffect3Label;
private javax.swing.JSpinner qtlEffect3Spinner;
private javax.swing.JLabel qtlEffect4Label;
private javax.swing.JLabel qtlEffectsLabel;
private javax.swing.JLabel qtlPositionLabel;
private javax.swing.JSpinner qtlPositionSpinner;
private javax.swing.JTable qtlsTable;
private javax.swing.JButton removeQtlButton;
private javax.swing.JTextField simulatedCrossNameTextField;
// End of variables declaration//GEN-END:variables
}