/* * 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.event.ItemEvent; import java.awt.event.ItemListener; import java.util.Arrays; 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.Constants; import org.jax.qtl.scan.ScanOneResult; import org.jax.qtl.scan.ScanOneThreshold; /** * A panel for editing thresholds * @author <A HREF="mailto:keith.sheppard@jax.org">Keith Sheppard</A> */ public class ScanOneThresholdPanel extends javax.swing.JPanel { /** * every {@link java.io.Serializable} is supposed to have one of these */ private static final long serialVersionUID = -2795048577522996703L; private static final double DEFAULT_THRESHOLD_ALPHA = 0.05; private final ScanOneGraph scanOneGraph; private final ScanOneResult scanOneResult; private final boolean xPermutationsAreSeparate; private DefaultTableModel thresholdTableModel; private SpinnerNumberModel alphaThresholdSpinnerModel; /** * Constructor * @param scanOneGraph * the graph that we're building thresholds for */ public ScanOneThresholdPanel(ScanOneGraph scanOneGraph) { this.scanOneGraph = scanOneGraph; this.scanOneResult = scanOneGraph.getScanOneResult(); this.xPermutationsAreSeparate = this.scanOneResult.getXChromosomePValuesAreSeparate(); this.initComponents(); this.postGuiInit(); } /** * Take care of the GUI initialization that isn't handled by the * GUI builder */ private void postGuiInit() { final String[] thresholdTableHeader; if(this.xPermutationsAreSeparate) { thresholdTableHeader = new String[] { "Alpha", "Autosome LOD Score", "X Chromosome LOD Score" }; } else { thresholdTableHeader = new String[] { "Alpha", "LOD Score" }; } this.alphaThresholdSpinnerModel = new SpinnerNumberModel( 0.1, // initial value 0.0, // min 1.0, // max 0.05); // step size this.alphaValueSpinner.setModel(this.alphaThresholdSpinnerModel); this.alphaValueSpinner.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { ScanOneThresholdPanel.this.thresholdAlphaChanged(); } }); this.showThresholdLabelCheckBox.setSelected( this.scanOneGraph.getShowThresholdLabel()); this.showThresholdLabelCheckBox.addItemListener(new ItemListener() { /** * {@inheritDoc} */ public void itemStateChanged(ItemEvent e) { ScanOneThresholdPanel.this.scanOneGraph.setShowThresholdLabel( e.getStateChange() == ItemEvent.SELECTED); } }); this.thresholdTableModel = new DefaultTableModel( thresholdTableHeader, 0); this.thresholdListTable.setModel(this.thresholdTableModel); this.thresholdListTable.setSelectionMode( ListSelectionModel.SINGLE_SELECTION); this.thresholdListTable.getSelectionModel().addListSelectionListener( new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { ScanOneThresholdPanel.this.rowSelectionChanged(); } }); ScanOneThreshold[] thresholds = this.scanOneGraph.getThresholdsToRender(); if(thresholds != null && thresholds.length > 0) { for(int i = 0; i < thresholds.length; i++) { ThresholdTableCell[] row = this.createRow(thresholds[i]); this.thresholdTableModel.addRow(row); } this.thresholdListTable.getSelectionModel().setSelectionInterval( 0, 0); } this.rowSelectionChanged(); } /** * respond to a change in row selection */ private void rowSelectionChanged() { ScanOneThreshold selectedThreshold = this.getSelectedThreshold(); if(selectedThreshold != null) { this.alphaThresholdSpinnerModel.setValue( Double.valueOf(selectedThreshold.getAlphaThreshold())); this.alphaValueLabel.setEnabled(true); this.alphaValueSpinner.setEnabled(true); this.removeThresholdButton.setEnabled(true); } else { this.alphaValueLabel.setEnabled(false); this.alphaValueSpinner.setEnabled(false); this.removeThresholdButton.setEnabled(false); } } /** * Get the selected threshold value * @return * the selected value or null if no value is selected */ private ScanOneThreshold getSelectedThreshold() { int selectedRow = this.thresholdListTable.getSelectedRow(); if(selectedRow >= 0) { ThresholdTableCell cell = (ThresholdTableCell)this.thresholdTableModel.getValueAt( selectedRow, 0); return cell.getThreshold(); } else { return null; } } /** * update the selected row using the current alpha value */ private void updateSelectedRow() { int selectedRow = this.thresholdListTable.getSelectedRow(); if(selectedRow >= 0) { ScanOneThreshold thresholdUpdate = this.scanOneResult.calculateThreshold( this.alphaThresholdSpinnerModel.getNumber().doubleValue(), this.scanOneGraph.getLodColumnName()); int columnCount = this.thresholdTableModel.getColumnCount(); for(int column = 0; column < columnCount; column++) { ThresholdTableCell cell = (ThresholdTableCell)this.thresholdTableModel.getValueAt( selectedRow, column); cell.setThreshold(thresholdUpdate); } } this.thresholdListTable.repaint(); } /** * Create a new table row from the given threshold value * @param threshold * the threshold to create a row for * @return * the row */ private ThresholdTableCell[] createRow(ScanOneThreshold threshold) { final ThresholdTableCell[] row = new ThresholdTableCell[ threshold.getXChromosomePValuesAreSeparate() ? 3 : 2]; for(int i = 0; i < row.length; i++) { row[i] = new ThresholdTableCell(threshold, i); } return row; } /** * a private cell class for the threshold table */ private static class ThresholdTableCell { private volatile ScanOneThreshold threshold; private final int tableColumn; /** * Constructor * @param threshold * the threshold * @param tableColumn * the cells column in the table */ public ThresholdTableCell(ScanOneThreshold threshold, int tableColumn) { this.threshold = threshold; this.tableColumn = tableColumn; } /** * @return the tableColumn */ public int getTableColumn() { return this.tableColumn; } /** * @return the threshold */ public ScanOneThreshold getThreshold() { return this.threshold; } /** * @param threshold the threshold to set */ public void setThreshold(ScanOneThreshold threshold) { this.threshold = threshold; } /** * {@inheritDoc} */ @Override public String toString() { switch(this.tableColumn) { case 0: return Constants.THREE_DIGIT_FORMATTER.format( this.threshold.getAlphaThreshold()); case 1: return Constants.THREE_DIGIT_FORMATTER.format( this.threshold.getAutosomeLodValue()); case 2: return Constants.THREE_DIGIT_FORMATTER.format( this.threshold.getXChromosomeLodValue()); default: return null; } } } /** * Respond to a change in the spinners alpha value */ private void thresholdAlphaChanged() { this.updateSelectedRow(); this.sendThresholdsToGraph(); } /** * Remove rows that are currently selected */ private void removeSelectedThresholds() { int[] selectedRows = this.thresholdListTable.getSelectedRows(); Arrays.sort(selectedRows); for(int rowIndex = selectedRows.length - 1; rowIndex >= 0; rowIndex--) { this.thresholdTableModel.removeRow(selectedRows[rowIndex]); } this.sendThresholdsToGraph(); } /** * Write all of the thresholds currently in the table to a graph */ private void sendThresholdsToGraph() { int rowCount = this.thresholdTableModel.getRowCount(); ScanOneThreshold[] thresholds = new ScanOneThreshold[rowCount]; for(int row = 0; row < rowCount; row++) { ThresholdTableCell currCell = (ThresholdTableCell)this.thresholdTableModel.getValueAt(row, 0); thresholds[row] = currCell.getThreshold(); } this.scanOneGraph.setThresholdsToRender(thresholds); } /** * 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() { alphaValueLabel = new javax.swing.JLabel(); alphaValueSpinner = new javax.swing.JSpinner(); showThresholdLabelCheckBox = new javax.swing.JCheckBox(); thresholdListScrollPanel = new javax.swing.JScrollPane(); thresholdListTable = new javax.swing.JTable(); addThresholdButton = new javax.swing.JButton(); removeThresholdButton = new javax.swing.JButton(); alphaValueLabel.setText("Alpha Threshold:"); showThresholdLabelCheckBox.setText("Show Threshold Label"); thresholdListScrollPanel.setViewportView(thresholdListTable); addThresholdButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/action/add-16x16.png"))); // NOI18N addThresholdButton.setText("New Threshold"); addThresholdButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { addThresholdButtonActionPerformed(evt); } }); removeThresholdButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/action/remove-16x16.png"))); // NOI18N removeThresholdButton.setText("Remove Selected"); removeThresholdButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { removeThresholdButtonActionPerformed(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(thresholdListScrollPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 474, Short.MAX_VALUE) .add(layout.createSequentialGroup() .add(alphaValueLabel) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(alphaValueSpinner, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 64, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(showThresholdLabelCheckBox)) .add(layout.createSequentialGroup() .add(addThresholdButton) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(removeThresholdButton))) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(layout.createSequentialGroup() .add(26, 26, 26) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(alphaValueLabel) .add(alphaValueSpinner, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(showThresholdLabelCheckBox)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(thresholdListScrollPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 199, Short.MAX_VALUE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(addThresholdButton) .add(removeThresholdButton)) .addContainerGap()) ); }// </editor-fold>//GEN-END:initComponents private void addThresholdButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addThresholdButtonActionPerformed ScanOneThreshold newThreshold = this.scanOneResult.calculateThreshold( DEFAULT_THRESHOLD_ALPHA, this.scanOneGraph.getLodColumnName()); ThresholdTableCell[] newRow = this.createRow(newThreshold); this.thresholdTableModel.addRow(newRow); int rowCount = this.thresholdTableModel.getRowCount(); this.thresholdListTable.getSelectionModel().setSelectionInterval( rowCount - 1, rowCount - 1); this.sendThresholdsToGraph(); }//GEN-LAST:event_addThresholdButtonActionPerformed private void removeThresholdButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeThresholdButtonActionPerformed this.removeSelectedThresholds(); }//GEN-LAST:event_removeThresholdButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton addThresholdButton; private javax.swing.JLabel alphaValueLabel; private javax.swing.JSpinner alphaValueSpinner; private javax.swing.JButton removeThresholdButton; private javax.swing.JCheckBox showThresholdLabelCheckBox; private javax.swing.JScrollPane thresholdListScrollPanel; private javax.swing.JTable thresholdListTable; // End of variables declaration//GEN-END:variables }