package au.com.acpfg.misc.spectra.peakextractor; import java.awt.Component; import java.awt.Dimension; import java.awt.GridLayout; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.knime.core.data.DataColumnSpec; import org.knime.core.data.DataTableSpec; import org.knime.core.data.DataType; import org.knime.core.node.InvalidSettingsException; import org.knime.core.node.NodeDialogPane; import org.knime.core.node.NodeLogger; import org.knime.core.node.NodeSettingsRO; import org.knime.core.node.NodeSettingsWO; import org.knime.core.node.NotConfigurableException; import org.knime.core.node.defaultnodesettings.DefaultNodeSettingsPane; import org.knime.core.node.util.DataColumnSpecListCellRenderer; import au.com.acpfg.misc.spectra.SpectralDataInterface; /** * <code>NodeDialog</code> for the "SpectralPeakExtractor" Node. * Extracts data defining a peak from any cell supporting SpectralDataInterface (defined in the SpectraReader node) * * This node dialog derives from {@link DefaultNodeSettingsPane} which allows * creation of a simple dialog with standard components. If you need a more * complex dialog please derive directly from * {@link org.knime.core.node.NodeDialogPane}. * * @author Andrew Cassin */ public class SpectralPeakExtractorNodeDialog extends NodeDialogPane { /** The node logger for this class. */ private static final NodeLogger LOGGER = NodeLogger .getLogger(SpectralPeakExtractorNodeDialog.class); /** List of numeric columns. */ private final JList m_spectraList; /** The spectra columns' model. */ private final DefaultListModel m_spectraMdl; /** Keeps shows the currently selected peaks */ private final JPanel m_peaks_panel; /** Keeps column data cell to interval panel settings. */ private final LinkedHashMap<String, PeakPanel> m_peaks; /** * Creates a new peak extraction dialog. */ SpectralPeakExtractorNodeDialog() { super(); m_peaks = new LinkedHashMap<String, PeakPanel>(); // peak panel in tab final JPanel peakPanel = new JPanel(new GridLayout(1, 1)); // spectral column list m_spectraMdl = new DefaultListModel(); m_spectraMdl.addElement("<empty>"); m_spectraList = new JList(m_spectraMdl); /** * Override renderer to plot number of defined bins. */ class SpectraListCellRenderer extends DataColumnSpecListCellRenderer { /** * {@inheritDoc} */ @Override public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, final boolean cellHasFocus) { Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); String name = ((DataColumnSpec)value).getName(); PeakPanel p = m_peaks.get(name); if (p != null) { int bins = p.getNumPeaks(); if (bins > 0) { String text = getText() + " ("; if (bins == 1) { text += bins + " peaks defined)"; } else { text += bins + " peaks defined)"; } } } return c; } } m_spectraList.setCellRenderer(new SpectraListCellRenderer()); m_spectraList.addListSelectionListener(new ListSelectionListener() { /** * */ public void valueChanged(final ListSelectionEvent e) { columnChanged(); peakPanel.validate(); peakPanel.repaint(); } }); m_spectraList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); final JScrollPane spectraScroll = new JScrollPane(m_spectraList); spectraScroll.setMinimumSize(new Dimension(300, 155)); spectraScroll .setBorder(BorderFactory.createTitledBorder(" Suitable Columns ")); // peaks to extract (they are permitted to overlap) m_peaks_panel = new JPanel(new GridLayout(1, 1)); m_peaks_panel.setBorder(BorderFactory.createTitledBorder(" Peaks to be extracted ")); m_peaks_panel.setMinimumSize(new Dimension(350, 300)); m_peaks_panel.setPreferredSize(new Dimension(350, 300)); JSplitPane split = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, spectraScroll, m_peaks_panel); peakPanel.add(split); super.addTab(" Select Spectra Column ", peakPanel); } private void columnChanged() { m_peaks_panel.removeAll(); Object o = m_spectraList.getSelectedValue(); if (o == null) { m_peaks_panel.setBorder(BorderFactory .createTitledBorder(" Select Peak ")); } else { m_peaks_panel.setBorder(null); m_peaks_panel.add(createPeakPanel((DataColumnSpec)o)); } } private PeakPanel createPeakPanel(final DataColumnSpec cspec) { String name = cspec.getName(); PeakPanel p; if (m_peaks.containsKey(name)) { p = m_peaks.get(name); } else { p = new PeakPanel(name, m_spectraList, m_peaks_panel, cspec.getType()); m_peaks.put(name, p); } p.validate(); p.repaint(); return p; } /** * @param settings to read intervals from * @param specs The input table spec * @see NodeDialogPane#loadSettingsFrom(NodeSettingsRO, DataTableSpec[]) * @throws NotConfigurableException if the spec contains no columns */ @Override protected void loadSettingsFrom(final NodeSettingsRO settings, final DataTableSpec[] specs) throws NotConfigurableException { // numeric columns' settings m_peaks.clear(); m_spectraMdl.removeAllElements(); for (int i = 0; i < specs[0].getNumColumns(); i++) { DataColumnSpec cspec = specs[0].getColumnSpec(i); //LOGGER.info(cspec.getType()); if (cspec.getType().isCompatible(SpectralDataInterface.class)) { m_spectraMdl.addElement(cspec); } } // no column found for peak if (m_spectraMdl.getSize() == 0) { throw new NotConfigurableException( "No suitable column found to define peaks."); } String[] columns = settings.getStringArray( SpectralPeakExtractorNodeModel.SPECTRA_COLUMNS, (String[])null); // if numeric columns in settings, select first if (columns != null && columns.length > 0) { for (int i = 0; i < columns.length; i++) { if (!specs[0].containsName(columns[i])) { continue; } NodeSettingsRO col; DataType type = specs[0].getColumnSpec(columns[i]).getType(); try { // TODO... always throws... maybe model bug? col = settings.getNodeSettings(columns[i]); } catch (InvalidSettingsException ise) { LOGGER.warn("NodeSettings not available for column: " + columns[i]+" "+ise.getMessage()); continue; } PeakPanel p = new PeakPanel(columns[i], m_spectraList, m_peaks_panel, type); m_peaks.put(columns[i], p); for (String peakId : col.keySet()) { //LOGGER.info("loading got peak "+peakId); try { NodeSettingsRO pset = col.getNodeSettings(peakId); p.add(new PeakWindow(pset)); } catch (InvalidSettingsException e) { e.printStackTrace(); } } DataColumnSpec cspec = specs[0].getColumnSpec(columns[i]); // select column and scroll to position m_spectraList.setSelectedValue(cspec, true); } } getPanel().validate(); getPanel().repaint(); } /** * @param settings write intervals to * @throws InvalidSettingsException if a bin name is empty * @see NodeDialogPane#saveSettingsTo(NodeSettingsWO) */ @Override protected void saveSettingsTo(final NodeSettingsWO settings) throws InvalidSettingsException { LinkedHashSet<String> colList = new LinkedHashSet<String>(); for (String cell : m_peaks.keySet()) { PeakPanel p = m_peaks.get(cell); // only if at least 1 peak is defined if (p.getNumPeaks() > 0) { //LOGGER.info("saving peaks for column: <"+cell+">"); colList.add(cell); NodeSettingsWO set = settings.addNodeSettings(cell); for (int j=0; j<p.getNumPeaks(); j++) { PeakItemPanel peak = p.getPeak(j); String peak_name = peak.getName() + "_" + j; //LOGGER.info("saving "+peak_name); NodeSettingsWO peak_settings = set.addNodeSettings(peak_name); peak.saveToSettings(peak_settings); } } } // save spectra columns (usually only a single column in the data, but who knows?) String[] columns = colList.toArray(new String[0]); //LOGGER.info(columns.length+" "+columns[0]); settings.addStringArray(SpectralPeakExtractorNodeModel.SPECTRA_COLUMNS, columns); } }