/*
* 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.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.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import org.jax.qtl.cross.SimulateMapCommandBuilder;
import org.jax.r.RCommand;
import org.jax.r.gui.RCommandEditorPanel;
import org.jax.util.TextWrapper;
/**
* Panel for editing a simulate map command
* @author <A HREF="mailto:keith.sheppard@jax.org">Keith Sheppard</A>
*/
public class SimulateMapPanel extends RCommandEditorPanel
{
/**
* our logger
*/
private static final Logger LOG = Logger.getLogger(
SimulateMapPanel.class.getName());
/**
* every {@link java.io.Serializable} is supposed to have one of these
*/
private static final long serialVersionUID = -2161949438215349056L;
private DefaultTableModel chromosomeTableModel;
private final SimulateMapCommandBuilder simulateMapCommandBuilder;
private final SpinnerNumberModel selectedChromosomeLengthModel =
new SpinnerNumberModel(
100.0, // value
0.0, // min
100.0, // max
1.0); // step
private final SpinnerNumberModel markersPerChromosomeModel =
new SpinnerNumberModel(
1, // value
1, // min
Integer.MAX_VALUE, // max
1); // step
/**
* Constructor
* @param simulateMapCommandBuilder
* command builder that this panel edits
*/
public SimulateMapPanel(SimulateMapCommandBuilder simulateMapCommandBuilder)
{
this.simulateMapCommandBuilder = simulateMapCommandBuilder;
this.initComponents();
this.postGuiInit();
}
/**
*
*/
private void postGuiInit()
{
this.markersPerChromosomeSpinner.setModel(
this.markersPerChromosomeModel);
this.markersPerChromosomeSpinner.setValue(
this.simulateMapCommandBuilder.getMarkersPerChromosome());
this.markersPerChromosomeModel.addChangeListener(
new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
SimulateMapPanel.this.updateCommand();
}
});
ItemListener updateOnItemChangeListener = new ItemListener()
{
public void itemStateChanged(ItemEvent e)
{
SimulateMapPanel.this.updateCommand();
}
};
this.includeTelomeresCheckBox.setSelected(
this.simulateMapCommandBuilder.getIncludeTelomereMarkers());
this.includeTelomeresCheckBox.addItemListener(
updateOnItemChangeListener);
this.useEqualMarkerSpacingCheckBox.setSelected(
this.simulateMapCommandBuilder.getUseEqualMarkerSpacing());
this.useEqualMarkerSpacingCheckBox.addItemListener(
updateOnItemChangeListener);
this.includeXChromosomeCheckBox.setSelected(
this.simulateMapCommandBuilder.getIncludeXChromosome());
this.includeXChromosomeCheckBox.addItemListener(
new ItemListener()
{
public void itemStateChanged(ItemEvent e)
{
SimulateMapPanel.this.updateCommand();
SimulateMapPanel.this.chromosomeTable.repaint();
}
});
this.selectedChromosomesLenthSpinner.setModel(
this.selectedChromosomeLengthModel);
this.selectedChromosomesLenthSpinner.addChangeListener(
new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
SimulateMapPanel.this.updateSelectedChromosomeLength();
SimulateMapPanel.this.chromosomeTable.repaint();
}
});
this.chromosomeTableModel = new DefaultTableModel()
{
/**
* every serializable is supposed to have one of these
*/
private static final long serialVersionUID = -4195503319407081829L;
/**
* {@inheritDoc}
*/
@Override
public boolean isCellEditable(int row, int column)
{
return false;
}
};
this.chromosomeTableModel.setColumnIdentifiers(new String[] {
"Chromosome",
"Length (cM)"});
this.chromosomeTable.setModel(this.chromosomeTableModel);
this.rebuildChromosomeTable();
this.chromosomeTable.getSelectionModel().addListSelectionListener(
new ListSelectionListener()
{
public void valueChanged(ListSelectionEvent e)
{
SimulateMapPanel.this.chromosomeSelectionChanged();
}
});
this.chromosomeTable.setSelectionMode(
ListSelectionModel.SINGLE_SELECTION);
this.chromosomeSelectionChanged();
}
private void rebuildChromosomeTable()
{
this.chromosomeTableModel.setRowCount(0);
double[] chromoLengths = this.simulateMapCommandBuilder.getChromosomeLengths();
for(int chromoLenIndex = 0; chromoLenIndex < chromoLengths.length; chromoLenIndex++)
{
this.chromosomeTableModel.addRow(new Object[] {
new ChromosomeTableCell(chromoLenIndex, 0),
new ChromosomeTableCell(chromoLenIndex, 1)});
}
}
/**
* update the length of the selected chromosome
*/
private void updateSelectedChromosomeLength()
{
double[] chromoLengths =
this.simulateMapCommandBuilder.getChromosomeLengths().clone();
int selectedIndex = this.chromosomeTable.getSelectedRow();
if(selectedIndex >= 0 && selectedIndex < chromoLengths.length)
{
chromoLengths[selectedIndex] =
this.selectedChromosomeLengthModel.getNumber().doubleValue();
LOG.fine("set chromosome length to: " + chromoLengths[selectedIndex]);
this.simulateMapCommandBuilder.setChromosomeLengths(chromoLengths);
this.fireCommandModified();
}
}
private void chromosomeSelectionChanged()
{
double[] chromoLengths =
this.simulateMapCommandBuilder.getChromosomeLengths();
int selectedIndex = this.chromosomeTable.getSelectedRow();
if(selectedIndex >= 0 && selectedIndex < chromoLengths.length)
{
this.selectedChromosomeLengthModel.setValue(
chromoLengths[selectedIndex]);
this.removeSelectedChromosomesButton.setEnabled(true);
this.selectedChromosomesLenthLabel.setEnabled(true);
this.selectedChromosomesLenthSpinner.setEnabled(true);
}
else
{
this.removeSelectedChromosomesButton.setEnabled(false);
this.selectedChromosomesLenthLabel.setEnabled(false);
this.selectedChromosomesLenthSpinner.setEnabled(false);
}
}
private void updateCommand()
{
this.simulateMapCommandBuilder.setMarkersPerChromosome(
this.markersPerChromosomeModel.getNumber().intValue());
this.simulateMapCommandBuilder.setIncludeTelomereMarkers(
this.includeTelomeresCheckBox.isSelected());
this.simulateMapCommandBuilder.setUseEqualMarkerSpacing(
this.useEqualMarkerSpacingCheckBox.isSelected());
this.simulateMapCommandBuilder.setIncludeXChromosome(
this.includeXChromosomeCheckBox.isSelected());
this.fireCommandModified();
}
private void addChromosome()
{
this.insertRow(
this.simulateMapCommandBuilder.getChromosomeLengths().length);
}
private void removeSelectedChromosome()
{
double[] chromoLengths =
this.simulateMapCommandBuilder.getChromosomeLengths();
int selectedIndex = this.chromosomeTable.getSelectedRow();
if(selectedIndex >= 0 && selectedIndex < chromoLengths.length)
{
double[] newChromoLengths = new double[chromoLengths.length - 1];
for(int i = 0; i < chromoLengths.length; i++)
{
if(i < selectedIndex)
{
newChromoLengths[i] = chromoLengths[i];
}
else if(i > selectedIndex)
{
newChromoLengths[i - 1] = chromoLengths[i];
}
}
this.simulateMapCommandBuilder.setChromosomeLengths(newChromoLengths);
this.rebuildChromosomeTable();
this.fireCommandModified();
}
}
private void insertRow(int rowNumber)
{
double[] chromoLengths =
this.simulateMapCommandBuilder.getChromosomeLengths();
double[] newChromoLengths = new double[chromoLengths.length + 1];
for(int i = 0; i <= chromoLengths.length; i++)
{
if(i < rowNumber)
{
newChromoLengths[i] = chromoLengths[i];
}
else if(i == rowNumber)
{
newChromoLengths[i] = 100;
}
else
{
newChromoLengths[i] = chromoLengths[i - 1];
}
}
this.simulateMapCommandBuilder.setChromosomeLengths(newChromoLengths);
this.rebuildChromosomeTable();
this.fireCommandModified();
}
/**
* {@inheritDoc}
*/
public RCommand[] getCommands()
{
return new RCommand[] {this.simulateMapCommandBuilder.getCommand()};
}
/**
* The chromosome table cell
* @author <A HREF="mailto:keith.sheppard@jax.org">Keith Sheppard</A>
*/
private class ChromosomeTableCell
{
private final int row;
private final int column;
/**
* Constructor
* @param row
* the table row for this cell
* @param column
* the table column for this cell
*/
public ChromosomeTableCell(int row, int column)
{
super();
this.row = row;
this.column = column;
}
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
double[] chromoLengths =
SimulateMapPanel.this.simulateMapCommandBuilder.getChromosomeLengths();
if(this.row < 0 || this.row >= chromoLengths.length)
{
LOG.severe("chromosome row out of bounds: " + this.row);
return "chromosome row out of bounds";
}
else if(this.column == 0)
{
if(this.row == chromoLengths.length - 1 &&
SimulateMapPanel.this.includeXChromosomeCheckBox.isSelected())
{
return "X";
}
else
{
return Integer.toString(this.row + 1);
}
}
else if(this.column == 1)
{
return Double.toString(chromoLengths[this.row]);
}
else
{
LOG.severe("chromosome column out of bounds: " + this.column);
return "chromosome column out of bounds";
}
}
}
/**
* Validate the data in this panel
* @return
* true iff the data is valid
*/
public boolean validateData()
{
String validationErrorMessage = null;
if(this.simulateMapCommandBuilder.getChromosomeLengths().length == 0)
{
validationErrorMessage =
"Chromosome list cannot be empty. Please add at least one " +
"chromosome or cancel.";
}
if(validationErrorMessage != null)
{
JOptionPane.showMessageDialog(
this,
TextWrapper.wrapText(
validationErrorMessage,
TextWrapper.DEFAULT_DIALOG_COLUMN_COUNT),
"Validation Failed",
JOptionPane.WARNING_MESSAGE);
return false;
}
else
{
return true;
}
}
/**
* 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 markersPerChromosomeLabel = new javax.swing.JLabel();
markersPerChromosomeSpinner = new javax.swing.JSpinner();
includeTelomeresCheckBox = new javax.swing.JCheckBox();
useEqualMarkerSpacingCheckBox = new javax.swing.JCheckBox();
includeXChromosomeCheckBox = new javax.swing.JCheckBox();
selectedChromosomesLenthLabel = new javax.swing.JLabel();
selectedChromosomesLenthSpinner = new javax.swing.JSpinner();
addChromosomeButton = new javax.swing.JButton();
removeSelectedChromosomesButton = new javax.swing.JButton();
javax.swing.JScrollPane chromosomesScrollPane = new javax.swing.JScrollPane();
chromosomeTable = new javax.swing.JTable();
markersPerChromosomeLabel.setText("Markers Per Chromosome:");
includeTelomeresCheckBox.setText("Include Telomere Markers");
useEqualMarkerSpacingCheckBox.setText("Use Equal Marker Spacing");
includeXChromosomeCheckBox.setText("Include X Chromosome");
selectedChromosomesLenthLabel.setText("Selected Chromosome Length (cM):");
addChromosomeButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/action/add-16x16.png"))); // NOI18N
addChromosomeButton.setText("New Chromosome");
addChromosomeButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
addChromosomeButtonActionPerformed(evt);
}
});
removeSelectedChromosomesButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/action/remove-16x16.png"))); // NOI18N
removeSelectedChromosomesButton.setText("Remove Selected");
removeSelectedChromosomesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
removeSelectedChromosomesButtonActionPerformed(evt);
}
});
chromosomeTable.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
},
new String [] {
}
));
chromosomesScrollPane.setViewportView(chromosomeTable);
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(chromosomesScrollPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 626, Short.MAX_VALUE)
.add(layout.createSequentialGroup()
.add(markersPerChromosomeLabel)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(markersPerChromosomeSpinner, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 75, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.add(layout.createSequentialGroup()
.add(includeTelomeresCheckBox)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(useEqualMarkerSpacingCheckBox))
.add(layout.createSequentialGroup()
.add(selectedChromosomesLenthLabel)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(selectedChromosomesLenthSpinner, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 75, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.add(layout.createSequentialGroup()
.add(addChromosomeButton)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(removeSelectedChromosomesButton))
.add(includeXChromosomeCheckBox))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup()
.addContainerGap()
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(markersPerChromosomeLabel)
.add(markersPerChromosomeSpinner, 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(includeTelomeresCheckBox)
.add(useEqualMarkerSpacingCheckBox))
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(includeXChromosomeCheckBox)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(selectedChromosomesLenthLabel)
.add(selectedChromosomesLenthSpinner, 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(chromosomesScrollPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 205, Short.MAX_VALUE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(addChromosomeButton)
.add(removeSelectedChromosomesButton))
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
private void addChromosomeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addChromosomeButtonActionPerformed
this.addChromosome();
}//GEN-LAST:event_addChromosomeButtonActionPerformed
private void removeSelectedChromosomesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeSelectedChromosomesButtonActionPerformed
this.removeSelectedChromosome();
}//GEN-LAST:event_removeSelectedChromosomesButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton addChromosomeButton;
private javax.swing.JTable chromosomeTable;
private javax.swing.JCheckBox includeTelomeresCheckBox;
private javax.swing.JCheckBox includeXChromosomeCheckBox;
private javax.swing.JSpinner markersPerChromosomeSpinner;
private javax.swing.JButton removeSelectedChromosomesButton;
private javax.swing.JLabel selectedChromosomesLenthLabel;
private javax.swing.JSpinner selectedChromosomesLenthSpinner;
private javax.swing.JCheckBox useEqualMarkerSpacingCheckBox;
// End of variables declaration//GEN-END:variables
}