package org.signalml.app.view.montage;
import static org.signalml.app.util.i18n.SvarogI18n._;
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import org.signalml.app.SvarogApplication;
import org.signalml.app.config.ManagerOfPresetManagers;
import org.signalml.app.config.preset.Preset;
import org.signalml.app.config.preset.PresetManager;
import org.signalml.app.config.preset.managers.EegSystemsPresetManager;
import org.signalml.app.config.preset.managers.FFTSampleFilterPresetManager;
import org.signalml.app.config.preset.managers.PredefinedTimeDomainFiltersPresetManager;
import org.signalml.app.config.preset.managers.TimeDomainSampleFilterPresetManager;
import org.signalml.app.document.signal.SignalDocument;
import org.signalml.app.model.components.validation.ValidationErrors;
import org.signalml.app.model.document.OpenDocumentDescriptor;
import org.signalml.app.model.montage.MontageDescriptor;
import org.signalml.app.view.common.components.presets.AbstractPanelWithPresets;
import org.signalml.app.view.common.components.presets.ComplexPresetControlsPanel;
import org.signalml.app.view.common.dialogs.errors.Dialogs;
import org.signalml.app.view.common.dialogs.errors.ValidationErrorsDialog;
import org.signalml.app.view.montage.filters.EditFFTSampleFilterDialog;
import org.signalml.app.view.montage.filters.EditTimeDomainSampleFilterDialog;
import org.signalml.app.view.workspace.ViewerFileChooser;
import org.signalml.domain.montage.Montage;
import org.signalml.domain.montage.SourceMontage;
import org.signalml.domain.montage.filter.FFTSampleFilter;
import org.signalml.domain.montage.filter.TimeDomainSampleFilter;
import org.signalml.domain.montage.system.ChannelFunction;
import org.signalml.domain.montage.system.EegSystem;
import org.signalml.domain.montage.system.IChannelFunction;
import org.signalml.plugin.export.SignalMLException;
import org.signalml.util.Util;
public class SignalMontagePanel extends AbstractPanelWithPresets {
/**
* This dialog is used when edititing
* {@link FFTSampleFilter FFTSampleFilter's} parameters.
*/
private EditFFTSampleFilterDialog editFFTSampleFilterDialog;
/**
* This dialog is used when editing {@link TimeDomainSampleFilter}
* parameters.
*/
private EditTimeDomainSampleFilterDialog editTimeDomainSampleFilterDialog;
/**
* A panel for editing the signal's montage.
*/
protected MontageEditionPanel montageEditionPanel;
protected MontageFiltersPanel filtersPanel;
protected MontageMiscellaneousPanel miscellaneousPanel;
protected JTabbedPane tabbedPane;
private SignalDocument signalDocument;
private Montage currentMontage;
private FFTSampleFilterPresetManager fftFilterPresetManager;
/**
* A {@link PresetManager} managing the user-defined
* {@link TimeDomainSampleFilter} presets.
*/
private TimeDomainSampleFilterPresetManager timeDomainSampleFilterPresetManager;
/**
* A {@link PresetManager} managing the predefined
* {@link TimeDomainSampleFilter TimeDomainSampleFilters}.
*/
private PredefinedTimeDomainFiltersPresetManager predefinedTimeDomainSampleFilterPresetManager;
/**
* The preset manager which manages the available {@link EegSystem EEG systems}.
*/
private EegSystemsPresetManager eegSystemsPresetManager;
private ValidationErrorsDialog errorsDialog;
public SignalMontagePanel(ViewerFileChooser fileChooser) {
super(SvarogApplication.getManagerOfPresetsManagers().getMontagePresetManager());
ManagerOfPresetManagers managerOfPresetsManagers = SvarogApplication.getManagerOfPresetsManagers();
this.predefinedTimeDomainSampleFilterPresetManager = managerOfPresetsManagers.getPredefinedTimeDomainSampleFilterPresetManager();
this.eegSystemsPresetManager = managerOfPresetsManagers.getEegSystemsPresetManager();
this.timeDomainSampleFilterPresetManager = managerOfPresetsManagers.getTimeDomainSampleFilterPresetManager();
this.fftFilterPresetManager = managerOfPresetsManagers.getFftFilterPresetManager();
setFileChooser(fileChooser);
this.setLayout(new BorderLayout());
this.add(createInterface(), BorderLayout.CENTER);
this.add(getPresetControlsPanel(), BorderLayout.SOUTH);
}
protected JPanel createInterface() {
JPanel interfacePanel = new JPanel();
interfacePanel.setLayout(new BorderLayout());
interfacePanel.setPreferredSize(new Dimension(800, 500));
tabbedPane = new JTabbedPane();
filtersPanel = new MontageFiltersPanel(predefinedTimeDomainSampleFilterPresetManager);
filtersPanel.setEditFFTSampleFilterDialog(getEditFFTSampleFilterDialog());
filtersPanel.setTimeDomainSampleFilterDialog(getEditTimeDomainSampleFilterDialog());
montageEditionPanel = new MontageEditionPanel();
montageEditionPanel.setErrorsDialog(getErrorsDialog());
miscellaneousPanel = new MontageMiscellaneousPanel();
tabbedPane.addTab(_("Montage"), montageEditionPanel);
tabbedPane.addTab(_("Filters"), filtersPanel);
tabbedPane.addTab(_("Miscellaneous"), miscellaneousPanel);
interfacePanel.add(tabbedPane);
return interfacePanel;
}
@Override
protected ComplexPresetControlsPanel getPresetControlsPanel() {
if (presetControlsPanel == null)
presetControlsPanel = new ComplexPresetControlsPanel(this, presetManager, true);
return presetControlsPanel;
}
public FFTSampleFilterPresetManager getFftFilterPresetManager() {
return fftFilterPresetManager;
}
public void setFftFilterPresetManager(FFTSampleFilterPresetManager fftFilterPresetManager) {
this.fftFilterPresetManager = fftFilterPresetManager;
}
/**
* Returns the {@link TimeDomainSampleFilterPresetManager} used by this
* SignalMontageDialog.
* @return the {@link TimeDomainSampleFilterPresetManager} used
*/
public TimeDomainSampleFilterPresetManager getTimeDomainSampleFilterPresetManager() {
return timeDomainSampleFilterPresetManager;
}
/**
* Sets a {@link TimeDomainSampleFilterPresetManager} to be used by this
* SignalMontageDialog.
* @param timeDomainSampleFilterPresetManager
* the {@link TimeDomainSampleFilterPresetManager} to be used
*/
public void setTimeDomainSampleFilterPresetManager(TimeDomainSampleFilterPresetManager timeDomainSampleFilterPresetManager) {
this.timeDomainSampleFilterPresetManager = timeDomainSampleFilterPresetManager;
}
protected EditFFTSampleFilterDialog getEditFFTSampleFilterDialog() {
if (editFFTSampleFilterDialog == null) {
editFFTSampleFilterDialog = new EditFFTSampleFilterDialog(this.getParentWindow(), true);
editFFTSampleFilterDialog.setFileChooser(getFileChooser());
}
return editFFTSampleFilterDialog;
}
/**
* Returns the {@link EditTimeDomainSampleFilterDialog} used by
* this SignalMontageDialog.
* @return the {@link EditTimeDomainSampleFilterDialog} used
*/
protected EditTimeDomainSampleFilterDialog getEditTimeDomainSampleFilterDialog() {
if (editTimeDomainSampleFilterDialog == null) {
editTimeDomainSampleFilterDialog = new EditTimeDomainSampleFilterDialog(this.getParentWindow(), true);
editTimeDomainSampleFilterDialog.setFileChooser(getFileChooser());
}
return editTimeDomainSampleFilterDialog;
}
/**
* Sets the sampling frequency used by the filters in this montage.
* @param samplingFrequency sampling frequency to be used
*/
public void setSamplingFrequency(float samplingFrequency) {
filtersPanel.setCurrentSamplingFrequency(samplingFrequency);
}
/**
* Returns the current sampling frequency used by the filters in this montage.
* @return the sampling frequency
*/
public float getSamplingFrequency() {
return filtersPanel.getCurrentSamplingFrequency();
}
/**
* Returns the current montage.
* @return the current montage
*/
public Montage getCurrentMontage() {
return currentMontage;
}
/**
* Returns the {@link EegSystemsPresetManager} used by this dialog.
* @return the {@link EegSystemsPresetManager} used by this dialog
*/
public EegSystemsPresetManager getEegSystemsPresetManager() {
return eegSystemsPresetManager;
}
/**
* Returns the validation errors dialog.
* If it doesn't exist it is created.
* @return the errors dialog
*/
protected synchronized ValidationErrorsDialog getErrorsDialog() {
if (errorsDialog == null) {
errorsDialog = new ValidationErrorsDialog(this.getParentWindow(), true);
}
return errorsDialog;
}
public void fillPanelFromModel(Object model) throws SignalMLException {
if (model instanceof Montage) {
this.currentMontage = new Montage((Montage) model);
setMontageToPanels(currentMontage);
} else {
final MontageDescriptor descriptor = (MontageDescriptor) model;
final Montage montage = descriptor.getMontage();
final SignalDocument signalDocument = descriptor.getSignalDocument();
final boolean signalBound = (signalDocument != null);
if (montage == null)
this.currentMontage = new Montage(signalBound ?
new SourceMontage(signalDocument) : new SourceMontage());
else
this.currentMontage = new Montage(montage);
this.signalDocument = signalDocument;
//getOkButton().setVisible(signalBound);
//getRootPane().setDefaultButton(signalBound ? getOkButton() : getCancelButton());
montageEditionPanel.setSignalBound(signalBound);
filtersPanel.setSignalBound(signalBound);
filtersPanel.setCurrentSamplingFrequency(signalBound ?
signalDocument.getSamplingFrequency() : 128.0F);
}
if (signalDocument != null && !this.currentMontage.isCompatible(signalDocument))
this.currentMontage.adapt(signalDocument);
setMontageToPanels(this.currentMontage);
}
public void setMontageToPanels(Montage montage) {
if (montage != null && montage.getEegSystemName() != null) {
EegSystem system = (EegSystem) eegSystemsPresetManager.getPresetByName(montage.getEegSystemFullName());
montage.setEegSystem(system);
}
montageEditionPanel.setMontageToPanels(montage);
filtersPanel.setMontage(montage);
miscellaneousPanel.setMontage(montage);
}
public void fillModelFromPanel(Object model) throws SignalMLException {
if (model instanceof MontageDescriptor) {
MontageDescriptor descriptor = (MontageDescriptor) model;
// montage was edited immediately for the most part
descriptor.setMontage(currentMontage);
}
else if (model instanceof OpenDocumentDescriptor) {
OpenDocumentDescriptor openDocumentDescriptor = (OpenDocumentDescriptor) model;
openDocumentDescriptor.getOpenSignalDescriptor().setMontage(getCurrentMontage());
}
}
public void validate(Object model, ValidationErrors errors) throws SignalMLException {
// validate montage table
if (currentMontage.getMontageChannelCount() == 0) {
errors.addError(_("The montage is empty. Please add some target channels"));
}
String description = miscellaneousPanel.getEditDescriptionPanel().getTextPane().getText();
if (description != null && !description.isEmpty()) {
if (Util.hasSpecialChars(description)) {
errors.addError(_("Description must not contain control characters"));
}
}
}
@Override
public Preset getPreset() throws SignalMLException {
Montage preset = new Montage(getCurrentMontage());
ValidationErrors errors = new ValidationErrors();
validate(preset, errors);
if (errors.hasErrors()) {
getErrorsDialog().showDialog(errors, true);
return null;
}
return preset;
}
@Override
public void setPreset(Preset preset) throws SignalMLException {
fillPanelFromModel(preset);
}
@Override
public boolean isPresetCompatible(Preset preset) {
Montage montagePreset = (Montage) preset;
int presetChannelsCount = getNormalChannelsCount(montagePreset);
int thisChannelsCount = getNormalChannelsCount(getCurrentMontage());
if (presetChannelsCount != thisChannelsCount) {
Dialogs.showError(_("Preset is incompatible with this montage - bad channels count in the preset montage!"));
logger.error("Preset incompatible: current montage 'normal' channel count = " +
+ thisChannelsCount + " preset channel count = " + presetChannelsCount);
return false;
}
return true;
}
private int getNormalChannelsCount(Montage montage) {
int normalChannelsCount = 0;
for (int i = 0; i < montage.getSourceChannelCount(); i++) {
IChannelFunction channelFunction = montage.getSourceChannelFunctionAt(i);
if (channelFunction != ChannelFunction.ZERO && channelFunction != ChannelFunction.ONE)
normalChannelsCount++;
}
return normalChannelsCount;
}
}