package org.signalml.app.view.signal.signalselection; import static org.signalml.app.util.i18n.SvarogI18n._; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JComboBox; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.border.TitledBorder; import org.apache.log4j.Logger; import org.signalml.app.model.components.BlockSelectionModelProvider; import org.signalml.app.model.components.ChannelSelectionModelProvider; import org.signalml.app.model.components.PageSelectionModelProvider; import org.signalml.app.model.components.validation.ValidationErrors; import org.signalml.app.util.SwingUtils; import org.signalml.app.view.common.components.spinners.SpinnerNumberEditor; import org.signalml.domain.signal.BoundedSignalSelection; import org.signalml.domain.signal.space.SignalSpace; import org.signalml.domain.signal.space.SignalSpaceConstraints; import org.signalml.exception.SanityCheckException; import org.signalml.plugin.export.signal.SignalSelection; import org.signalml.plugin.export.signal.SignalSelectionType; import org.springframework.validation.Errors; /** * Panel which allows to select the parameters of a {@link SignalSelection * signal selection}. * Contains the {@link SignalSelectionTypePanel panel} which allows to select * the type of the selection. * Depending on this type activates the appropriate card in the card panel: * <ul> * <li>for a {@link SignalSelectionType#PAGE PAGE} selection - * the {@link #pageSignalSelectionPanel panel} which allows to select * the options of a page signal selection,</li> * <li>for a {@link SignalSelectionType#BLOCK BLOCK} selection - * the {@link #blockSignalSelectionPanel panel} which allows to select * the options of a block signal selection,</li> * <li>for a {@link SignalSelectionType#CHANNEL CHANNEL} selection - * the {@link #channelSignalSelectionPanel panel} which allows to select * the options of a channel signal selection.</li> * </ul> * * @author Michal Dobaczewski © 2007-2008 CC Otwarte Systemy Komputerowe Sp. z o.o. */ public class SignalSelectionPanel extends JPanel { private static final long serialVersionUID = 1L; protected static final Logger logger = Logger.getLogger(SignalSelectionPanel.class); /** * the card layout for {@link #cardPanel} */ private CardLayout cardLayout; /** * the panel with {@link #cardLayout CardLayout} and 3 cards: * <ul> * <li>the {@link #pageSignalSelectionPanel panel} which allows to select * the options of a page signal selection</li> * <li>the {@link #blockSignalSelectionPanel panel} which allows to select * the options of a block signal selection</li> * <li>the {@link #channelSignalSelectionPanel panel} which allows to select * the options of a channel signal selection</li> * </ul> */ private JPanel cardPanel; /** * the {@link SignalSelectionTypePanel panel} which allows to select * the {@link SignalSelectionType type} of the selection */ private SignalSelectionTypePanel signalSelectionTypePanel; /** * The {@link PageSignalSelectionPanel panel} which allows to select * the options of a page signal selection. * This panel is visible if {@link SignalSelectionType#PAGE PAGE} type * is selected. */ private PageSignalSelectionPanel pageSignalSelectionPanel; /** * The {@link BlockSignalSelectionPanel panel} which allows to select * the options of a block signal selection. * This panel is visible if {@link SignalSelectionType#BLOCK BLOCK} type * is selected. */ private BlockSignalSelectionPanel blockSignalSelectionPanel; /** * The {@link ChannelSignalSelectionPanel panel} which allows to select * the options of a channel signal selection. * This panel is visible if {@link SignalSelectionType#CHANNEL CHANNEL} * type is selected. */ private ChannelSignalSelectionPanel channelSignalSelectionPanel; /** * the {@link SignalSpaceConstraints parameters} of the signal */ private SignalSpaceConstraints currentConstraints; /** * the selection created from the current status of the fields in this * dialog */ private BoundedSignalSelection currentBss; /** * {@code true} if this panel should allow to * select a channel (for a channel selection), {@code false} otherwise */ private boolean withChannelSelection; /** * Constructor. Initializes the panel. * @param withChannelSelection {@code true} if this panel should allow to * select a channel (for a channel selection), {@code false} otherwise */ public SignalSelectionPanel(boolean withChannelSelection) { super(); this.withChannelSelection = withChannelSelection; initialize(); } /** * Initializes this panel with border layout and two sub-panels (from top * to bottom): * <ul> * <li>the {@link SignalSelectionTypePanel panel} which allows to select * the {@link SignalSelectionType type} of the selection,</li> * <li>the card panel with 3 cards: * <ul> * <li>the {@link #pageSignalSelectionPanel panel} which allows to select * the options of a page signal selection,</li> * <li>the {@link #blockSignalSelectionPanel panel} which allows to select * the options of a block signal selection,</li> * <li>the {@link #channelSignalSelectionPanel panel} which allows to select * the options of a channel signal selection.</li> * </ul></li></ul> * For every button in the {@link SignalSelectionTypePanel} adds a listener * which activates the appropriate card. */ private void initialize() { setLayout(new BorderLayout()); signalSelectionTypePanel = new SignalSelectionTypePanel(); add(signalSelectionTypePanel, BorderLayout.NORTH); pageSignalSelectionPanel = new PageSignalSelectionPanel(); blockSignalSelectionPanel = new BlockSignalSelectionPanel(); channelSignalSelectionPanel = new ChannelSignalSelectionPanel(withChannelSelection); cardLayout = new CardLayout(); cardPanel = new JPanel(); cardPanel.setLayout(cardLayout); cardPanel.setBorder(new TitledBorder(_("Selection parameters"))); cardPanel.add(pageSignalSelectionPanel, "page"); cardPanel.add(blockSignalSelectionPanel, "block"); cardPanel.add(channelSignalSelectionPanel, "channel"); signalSelectionTypePanel.getPageRadio().addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { cardLayout.show(cardPanel, "page"); } }); signalSelectionTypePanel.getBlockRadio().addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { cardLayout.show(cardPanel, "block"); } }); signalSelectionTypePanel.getChannelRadio().addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { cardLayout.show(cardPanel, "channel"); } }); add(cardPanel, BorderLayout.CENTER); } /** * Fills this panel (actually the sub-panels) with the data form the given * {@link BoundedSignalSelection model}: * <ul> * <li>Sets the model for * {@link PageSelectionModelProvider#getStartPageSpinnerModel() start * page spinner} and * {@link PageSelectionModelProvider#getLengthSpinnerModel() length spinner}. * <br>If it is a {@link SignalSelectionType#PAGE PAGE} selection the * {@link PageSelectionModelProvider provider} for the model is created * using the parameters from the given {@link BoundedSignalSelection selection}: * <ul> * <li>the maximum number of the {@link BoundedSignalSelection#getMaxPage() page} * that can be used,</li> * <li>the number of the {@link SignalSelection#getStartSegment(float) first * page} in the selection,</li> * <li>the {@link SignalSelection#getSegmentLength(float) number of pages} * in the selection,</li></ul> * otherwise default parameters are used. * </li> * <li>Sets the model for spinners in {@link BlockSignalSelectionPanel} * ({@link BlockSelectionModelProvider#getStartPageSpinnerModel() start * page spinner}, * {@link BlockSelectionModelProvider#getStartBlockSpinnerModel() * start block spinner} and {@link * BlockSelectionModelProvider#getLengthSpinnerModel() length spinner}). * <br>If it is a {@link SignalSelectionType#BLOCK BLOCK} selection the * {@link BlockSelectionModelProvider provider} for the model is created * using the parameters from the given {@link BoundedSignalSelection selection}: * <ul> * <li>the maximum number of the {@link BoundedSignalSelection#getMaxPage() * page} that can be used,</li> * <li>the maximum number of the {@link BoundedSignalSelection#getMaxBlock() * block} that can be used,</li> * <li>the {@link BoundedSignalSelection#getBlocksPerPage() number of blocks * in a page},</li> * <li>the number of the {@link SignalSelection#getStartSegment(float) first * page} in the selection,</li> * <li>the number of the first block in the selection,</li> * <li>the {@link SignalSelection#getSegmentLength(float) number of blocks} * in the selection),</li></ul> * otherwise default parameters are used. * </li> * <li>Sets the model for spinners in {@link ChannelSignalSelectionPanel} * ({@link ChannelSelectionModelProvider#getStartTimeSpinnerModel() start * time spinner} and {@link * ChannelSelectionModelProvider#getLengthSpinnerModel() length spinner}). * <br>If it is a {@link SignalSelectionType#CHANNEL CHANNEL} selection the * {@link ChannelSelectionModelProvider provider} for the model is created * using the parameters from the given {@link BoundedSignalSelection selection}: * <ul> * <li>the maximum {@link BoundedSignalSelection#getMaxTime() time} that * can be used,</li> * <li>the {@link BoundedSignalSelection#getSamplingFrequency() sampling * frequency},</li> * <li>the {@link BoundedSignalSelection#getChannels() names} of channels, * </li> * <li>the {@link SignalSelection#getPosition() starting position} of the * selection,</li> * <li>the {@link SignalSelection#getLength() length} of the selection,</li> * <li>the {@link SignalSelection#getChannel() channel} for the * selection,</li></ul> * otherwise default parameters are used. * </li> * <li>depending on the type sets the appropriate button in * {@link SignalSelectionTypePanel} to be selected.</li> * <li>If it is a {@code CHANNEL} selection sets the * {@link ChannelSelectionModelProvider#getChannelComboBoxModel() model} * for the {@link ChannelSignalSelectionPanel#getChannelComboBox() * combo-box}.</li> * </ul> * @param bss the bounded selection */ public void fillPanelFromModel(BoundedSignalSelection bss) { JSpinner startPageSpinner; JSpinner startBlockSpinner; JSpinner lengthSpinner; SignalSelection selection = bss.getSelection(); SignalSelectionType type = null; if (selection != null) { type = selection.getType(); } PageSelectionModelProvider pageSelectionModelProvider; if (type != null && type.isPage()) { pageSelectionModelProvider = new PageSelectionModelProvider( bss.getMaxPage(), selection.getStartSegment(bss.getPageSize()) + 1, selection.getSegmentLength(bss.getPageSize())); signalSelectionTypePanel.getPageRadio().setSelected(true); cardLayout.show(cardPanel, "page"); } else { pageSelectionModelProvider = new PageSelectionModelProvider( bss.getMaxPage(), 1, 1); } startPageSpinner = pageSignalSelectionPanel.getStartPageSpinner(); lengthSpinner = pageSignalSelectionPanel.getLengthSpinner(); SwingUtils.replaceSpinnerModel(startPageSpinner, pageSelectionModelProvider.getStartPageSpinnerModel()); startPageSpinner.setEditor(new SpinnerNumberEditor(startPageSpinner)); SwingUtils.replaceSpinnerModel(lengthSpinner, pageSelectionModelProvider.getLengthSpinnerModel()); lengthSpinner.setEditor(new SpinnerNumberEditor(lengthSpinner)); BlockSelectionModelProvider blockSelectionModelProvider; if (type != null && type.isBlock()) { float blockSize = ((float) bss.getPageSize()) / bss.getBlocksPerPage(); int startSegment = selection.getStartSegment(blockSize); blockSelectionModelProvider = new BlockSelectionModelProvider( bss.getMaxPage(), bss.getMaxBlock(), bss.getBlocksPerPage(), (startSegment / bss.getBlocksPerPage()) + 1, (startSegment % bss.getBlocksPerPage()) + 1, selection.getSegmentLength(blockSize)); signalSelectionTypePanel.getBlockRadio().setSelected(true); cardLayout.show(cardPanel, "block"); } else { blockSelectionModelProvider = new BlockSelectionModelProvider( bss.getMaxPage(), bss.getMaxBlock(), bss.getBlocksPerPage(), 1, 1, 1); } startPageSpinner = blockSignalSelectionPanel.getStartPageSpinner(); startBlockSpinner = blockSignalSelectionPanel.getStartBlockSpinner(); lengthSpinner = blockSignalSelectionPanel.getLengthSpinner(); SwingUtils.replaceSpinnerModel(startPageSpinner, blockSelectionModelProvider.getStartPageSpinnerModel()); startPageSpinner.setEditor(new SpinnerNumberEditor(startPageSpinner)); SwingUtils.replaceSpinnerModel(startBlockSpinner, blockSelectionModelProvider.getStartBlockSpinnerModel()); startBlockSpinner.setEditor(new SpinnerNumberEditor(startBlockSpinner)); SwingUtils.replaceSpinnerModel(lengthSpinner, blockSelectionModelProvider.getLengthSpinnerModel()); lengthSpinner.setEditor(new SpinnerNumberEditor(lengthSpinner)); ChannelSelectionModelProvider channelSelectionModelProvider; if (type != null && type.isChannel()) { channelSelectionModelProvider = new ChannelSelectionModelProvider( bss.getMaxTime(), bss.getSamplingFrequency(), bss.getChannels(), selection.getPosition(), selection.getLength(), selection.getChannel()); signalSelectionTypePanel.getChannelRadio().setSelected(true); cardLayout.show(cardPanel, "channel"); } else { channelSelectionModelProvider = new ChannelSelectionModelProvider( bss.getMaxTime(), bss.getSamplingFrequency(), bss.getChannels(), 0.0, 1.0, 0 //select first channel ); } JSpinner startTimeSpinner = channelSignalSelectionPanel.getStartTimeSpinner(); lengthSpinner = channelSignalSelectionPanel.getLengthSpinner(); SwingUtils.replaceSpinnerModel(startTimeSpinner, channelSelectionModelProvider.getStartTimeSpinnerModel()); startTimeSpinner.setEditor(new SpinnerNumberEditor(startTimeSpinner)); SwingUtils.replaceSpinnerModel(lengthSpinner, channelSelectionModelProvider.getLengthSpinnerModel()); lengthSpinner.setEditor(new SpinnerNumberEditor(lengthSpinner)); if (withChannelSelection) { JComboBox channelComboBox = channelSignalSelectionPanel.getChannelComboBox(); channelComboBox.setModel(channelSelectionModelProvider.getChannelComboBoxModel()); } if (type == null) { signalSelectionTypePanel.getPageRadio().setSelected(true); cardLayout.show(cardPanel, "page"); } } /** * Depending on the selected {@link SignalSelectionType type}: * <ul> * <li>if the {@link SignalSelectionTypePanel#getPageRadio() button} * for a {@link SignalSelectionType#PAGE PAGE} selection is selected: * <ul><li>creates the selection of that type,</li> * <li>sets the {@link SignalSelection#setPosition(float) starting position} * using the {@link PageSignalSelectionPanel#getStartPageSpinner() start * page spinner},</li> * <li>sets the {@link SignalSelection#setLength(float) length} * using the {@link PageSignalSelectionPanel#getLengthSpinner() length * spinner},</li></ul></li> * * <li>if the {@link SignalSelectionTypePanel#getBlockRadio() button} * for a {@link SignalSelectionType#BLOCK BLOCK} selection is selected: * <ul><li>creates the selection of that type,</li> * <li>sets the {@link SignalSelection#setPosition(float) starting position} * using the {@link BlockSignalSelectionPanel#getStartPageSpinner() start * page} and {@link BlockSignalSelectionPanel#getStartBlockSpinner() start * block} spinners,</li> * <li>sets the {@link SignalSelection#setLength(float) length} * using the {@link BlockSignalSelectionPanel#getLengthSpinner() length * spinner},</li></ul></li> * * <li>if the {@link SignalSelectionTypePanel#getChannelRadio() button} * for a {@link SignalSelectionType#CHANNEL CHANNEL} selection is selected: * <ul><li>creates the selection of that type,</li> * <li>sets the {@link SignalSelection#setPosition(float) starting position} * using the {@link ChannelSignalSelectionPanel#getStartTimeSpinner() start * time spinner},</li> * <li>sets the {@link SignalSelection#setLength(float) length} * using the {@link ChannelSignalSelectionPanel#getLengthSpinner() length * spinner},</li> * <li>sets the {@link SignalSelection#setChannel(int) channel} using the * {@link ChannelSignalSelectionPanel#getChannelComboBox() channel * combo-box},</ul></li></ul> * Stores the created selection in the {@link BoundedSignalSelection model}. * @param bss the model (bounded signal selection) */ public void fillModelFromPanel(BoundedSignalSelection bss) { SignalSelection selection = null; if (signalSelectionTypePanel.getPageRadio().isSelected()) { int startPage = (Integer) pageSignalSelectionPanel.getStartPageSpinner().getValue(); int length = (Integer) pageSignalSelectionPanel.getLengthSpinner().getValue(); selection = new SignalSelection(SignalSelectionType.PAGE); selection.setPosition((startPage - 1) * bss.getPageSize()); selection.setLength(length * bss.getPageSize()); selection.setChannel(SignalSelection.CHANNEL_NULL); } else if (signalSelectionTypePanel.getBlockRadio().isSelected()) { int startPage = (Integer) blockSignalSelectionPanel.getStartPageSpinner().getValue(); int startBlock = (Integer) blockSignalSelectionPanel.getStartBlockSpinner().getValue(); int length = (Integer) blockSignalSelectionPanel.getLengthSpinner().getValue(); float blockSize = ((float) bss.getPageSize()) / bss.getBlocksPerPage(); selection = new SignalSelection(SignalSelectionType.BLOCK); selection.setPosition((startPage - 1) * bss.getPageSize() + (startBlock - 1) * blockSize); selection.setLength(length * blockSize); selection.setChannel(SignalSelection.CHANNEL_NULL); } else if (signalSelectionTypePanel.getChannelRadio().isSelected()) { double startTime = (Double) channelSignalSelectionPanel.getStartTimeSpinner().getValue(); double length = (Double) channelSignalSelectionPanel.getLengthSpinner().getValue(); selection = new SignalSelection(SignalSelectionType.CHANNEL); selection.setPosition(startTime); selection.setLength(length); if (withChannelSelection) { int channel = channelSignalSelectionPanel.getChannelComboBox().getSelectedIndex(); selection.setChannel(channel); } } else { logger.error("Unexpected situation - nothing selected"); throw new SanityCheckException(); } bss.setSelection(selection); } /** * Creates the {@link BoundedSignalSelection bounded selection} based * on the {@link SignalSpace#getSelectionTimeSpace() selection} obtained * from the {@link SignalSpace model}. * In this bounded selections sets the {@link SignalSpaceConstraints * limitations} from the current constraints. * Calls {@link #fillPanelFromModel(BoundedSignalSelection) with this * selection}. * @param space the signal space */ public void fillPanelFromModel(SignalSpace space) { BoundedSignalSelection bss = new BoundedSignalSelection(space.getSelectionTimeSpace()); bss.setMaxTime(currentConstraints.getTimeSignalLength()); bss.setChannels(currentConstraints.getChannels()); bss.setPageSize(currentConstraints.getPageSize()); bss.setBlocksPerPage(currentConstraints.getBlocksPerPage()); bss.setMaxPage(currentConstraints.getMaxPage()); bss.setMaxBlock(currentConstraints.getMaxBlock()); bss.setSamplingFrequency(currentConstraints.getSamplingFrequency()); currentBss = bss; fillPanelFromModel(bss); } /** * Fills the {@link BoundedSignalSelection bounded selection} using * {@link #fillModelFromPanel(BoundedSignalSelection)} and sets the * {@link SignalSelection selection} from it in the {@link SignalSpace * model}. * @param space the model (signal space) */ public void fillModelFromPanel(SignalSpace space) { fillModelFromPanel(currentBss); space.setSelectionTimeSpace(currentBss.getSelection()); } /** * Sets the {@link SignalSpaceConstraints parameters} of the signal. * @param constraints the parameters of the signal */ public void setConstraints(SignalSpaceConstraints constraints) { currentConstraints = constraints; } /** * Validates this panel. * This panel is always valid. * @param errors the object in which errors are stored */ public void validatePanel(ValidationErrors errors) { // there is no validation - the dialog elements enforce valid values themselves } }