/*
* Copyright (C) 2013 Serdar
*
* This program 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 program 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 program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.fub.maps.project.detector.actions;
import de.fub.maps.project.detector.model.Detector;
import de.fub.maps.project.detector.model.inference.AbstractInferenceModel;
import de.fub.maps.project.detector.model.inference.features.FeatureProcess;
import de.fub.maps.project.detector.model.pipeline.postprocessors.tasks.Task;
import de.fub.maps.project.detector.model.pipeline.preprocessors.FilterProcess;
import de.fub.maps.project.detector.model.process.AbstractDetectorProcess;
import de.fub.maps.project.detector.model.xmls.DataSet;
import de.fub.maps.project.detector.model.xmls.DetectorDescriptor;
import de.fub.maps.project.detector.model.xmls.InferenceModelDescriptor;
import de.fub.maps.project.detector.model.xmls.ProcessDescriptor;
import de.fub.maps.project.detector.model.xmls.TransportMode;
import de.fub.maps.project.detector.utils.DetectorUtils;
import de.fub.maps.project.detector.wizards.detector.CommonDetectorInformationWizardPanel;
import de.fub.maps.project.detector.wizards.detector.DetectorTemplateWizardPanel;
import de.fub.maps.project.detector.wizards.detector.InferenceDataSetSelectionWizardPanel;
import de.fub.maps.project.detector.wizards.detector.InferenceModelFeatureSelectionWizardPanel;
import de.fub.maps.project.detector.wizards.detector.InferenceModelSelectionWizardPanel;
import de.fub.maps.project.detector.wizards.detector.PostprocessorSelectionWizardPanel;
import de.fub.maps.project.detector.wizards.detector.PreprocessorSelectionWizardPanel;
import de.fub.maps.project.detector.wizards.detector.TrainingSetSelectionWizardPanel;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import javax.swing.JComponent;
import javax.swing.event.ChangeListener;
import org.openide.DialogDisplayer;
import org.openide.WizardDescriptor;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionRegistration;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataObject;
import org.openide.nodes.Node;
import org.openide.util.ChangeSupport;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.openide.util.WeakListeners;
@ActionID(category = "Detector", id = "de.fub.maps.project.detector.actions.NewDetectorWizardAction")
@ActionRegistration(displayName = "#CLT_NewDetectorWizardAction_Name")
@ActionReference(path = "Projects/org-maps-project/Detector/Actions", position = 100)
@NbBundle.Messages({
"CLT_NewDetectorWizardAction_Name=New Detector...",
"CLT_New_Detector_Wizard_Title=New Detector Wizard"
})
public final class NewDetectorWizardAction implements ActionListener, WizardDescriptor.Iterator<WizardDescriptor>, PropertyChangeListener {
public static final String PROP_NAME_DATAOBJECT = "detector.wizard.dataObject";
public static final String PROP_NAME_CREATE_VIA_TEMPLATE = "create.via.template";
private WizardDescriptor wiz;
private int index;
private List<WizardDescriptor.Panel<WizardDescriptor>> panels;
private final ChangeSupport cs = new ChangeSupport(this);
private List<WizardDescriptor.Panel<WizardDescriptor>> viaTemplatePanels = null;
private List<WizardDescriptor.Panel<WizardDescriptor>> withoutTemplatePanels = null;
private final DataObject context;
public NewDetectorWizardAction(DataObject context) {
this.context = context;
}
@Override
@SuppressWarnings("unchecked")
public void actionPerformed(ActionEvent e) {
if (context != null) {
FileUtil.refreshFor(FileUtil.toFile(context.getPrimaryFile()));
panels = null;
index = 0;
wiz = new WizardDescriptor(NewDetectorWizardAction.this);
// {0} will be replaced by WizardDesriptor.Panel.getComponent().getName()
wiz.setTitleFormat(new MessageFormat("{0}"));
wiz.setTitle(Bundle.CLT_New_Detector_Wizard_Title());
wiz.putProperty(PROP_NAME_DATAOBJECT, context);
wiz.addPropertyChangeListener(WeakListeners.propertyChange(NewDetectorWizardAction.this, wiz));
if (DialogDisplayer.getDefault().notify(wiz) == WizardDescriptor.FINISH_OPTION) {
if (panels == withoutTemplatePanels) {
handleSimpleDetectorCreation();
} else if (panels == viaTemplatePanels) {
handleDetectorCreationViaTemplate();
}
FileUtil.refreshFor(FileUtil.toFile(context.getPrimaryFile()));
}
}
}
@SuppressWarnings("unchecked")
private void handleSimpleDetectorCreation() {
String detectorName = null;
String detectorDescription = null;
AbstractInferenceModel abstractInferenceModel = null;
List<FeatureProcess> selectedFeatureList = null;
List<FilterProcess> selectedFilterList = null;
List<Task> selectedTaskList = null;
Map<String, List<Node>> trainingsMap = null;
List<Node> inferenceDataSet = null;
for (int position = 0; position < withoutTemplatePanels.size(); position++) {
switch (position) {
case 0:
detectorName = (String) wiz.getProperty(CommonDetectorInformationWizardPanel.PROP_NAME_DETECTOR_NAME);
detectorDescription = (String) wiz.getProperty(CommonDetectorInformationWizardPanel.PROP_NAME_DETECTOR_DESCRIPTION);
break;
case 1:
abstractInferenceModel = (AbstractInferenceModel) wiz.getProperty(InferenceModelSelectionWizardPanel.PROP_NAME_INFERENCEMODEL);
break;
case 2:
selectedFeatureList = (List<FeatureProcess>) wiz.getProperty(InferenceModelFeatureSelectionWizardPanel.PROP_NAME_FEATURES);
break;
case 3:
selectedFilterList = (List<FilterProcess>) wiz.getProperty(PreprocessorSelectionWizardPanel.PROP_NAME_SELECTED_PREPROCESSORS);
break;
case 4:
selectedTaskList = (List<Task>) wiz.getProperty(PostprocessorSelectionWizardPanel.PROP_NAME_SELECTED_POSTPROCESSORS);
break;
case 5:
trainingsMap = (Map<String, List<Node>>) wiz.getProperty(TrainingSetSelectionWizardPanel.PROP_NAME_TRAININGS_SET);
break;
case 6:
inferenceDataSet = (List<Node>) wiz.getProperty(InferenceDataSetSelectionWizardPanel.PROP_NAME_INFERENCE_DATA);
break;
default:
throw new AssertionError();
}
}
if (detectorName != null && abstractInferenceModel != null) {
DetectorDescriptor detectorDescriptor = new DetectorDescriptor();
detectorDescriptor.setName(detectorName);
detectorDescriptor.setDescription(detectorDescription);
InferenceModelDescriptor inferenceModelDescriptor = abstractInferenceModel.getInferenceModelDescriptor();
if (inferenceModelDescriptor != null) {
try {
detectorDescriptor.setInferenceModel(inferenceModelDescriptor);
inferenceModelDescriptor.getFeatures().getFeatureList().clear();
addProcessDescriptorList(inferenceModelDescriptor.getFeatures().getFeatureList(), selectedFeatureList);
addProcessDescriptorList(detectorDescriptor.getPreprocessors().getPreprocessorList(), selectedFilterList);
addProcessDescriptorList(detectorDescriptor.getPostprocessors().getPostprocessorList(), selectedTaskList);
addTrainingsSet(detectorDescriptor, trainingsMap);
addInferenceDataset(detectorDescriptor, inferenceDataSet);
int lastIndexOf = detectorName.lastIndexOf(".");
detectorName = lastIndexOf > -1 ? detectorName.substring(0, lastIndexOf) : detectorName;
FileObject destFileObject = context.getPrimaryFile().createData(MessageFormat.format("{0}.dec", detectorName));
DetectorUtils.saveDetector(destFileObject, detectorDescriptor);
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
}
}
private void addProcessDescriptorList(List<ProcessDescriptor> detectorDescriptor, List< ? extends AbstractDetectorProcess<?, ?>> list) {
ProcessDescriptor processDescriptor = null;
if (list != null) {
for (AbstractDetectorProcess<?, ?> process : list) {
processDescriptor = process.getProcessDescriptor();
if (processDescriptor != null) {
detectorDescriptor.add(processDescriptor);
}
}
}
}
private void addTrainingsSet(DetectorDescriptor detectorDescriptor, Map<String, List<Node>> trainingsMap) {
if (trainingsMap != null) {
List<TransportMode> transportModeList = detectorDescriptor.getDatasets().getTrainingSet().getTransportModeList();
for (Entry<String, List<Node>> entry : trainingsMap.entrySet()) {
TransportMode transportMode = new TransportMode(entry.getKey());
transportModeList.add(transportMode);
for (Node node : entry.getValue()) {
DataObject dataObject = node.getLookup().lookup(DataObject.class);
if (dataObject != null) {
transportMode.getDataset().add(
new DataSet(dataObject.getPrimaryFile().getPath()));
}
}
}
}
}
private void addInferenceDataset(DetectorDescriptor detectorDescriptor, List<Node> inferenceDataSet) {
if (inferenceDataSet != null) {
List<DataSet> datasetList = detectorDescriptor.getDatasets().getInferenceSet().getDatasetList();
for (Node node : inferenceDataSet) {
DataObject dataObject = node.getLookup().lookup(DataObject.class);
if (dataObject != null) {
datasetList.add(new DataSet(
dataObject.getPrimaryFile().getPath()));
}
}
}
}
@SuppressWarnings({"unchecked", "empty-statement"})
private void handleDetectorCreationViaTemplate() {
String detectorName = null;
String detectorDescription = null;
Detector detectorTemplate = null;
Map<String, List<Node>> trainingsMap = null;
List<Node> inferenceDataSet = null;
for (int position = 0; position < viaTemplatePanels.size(); position++) {
switch (position) {
case 0:
detectorName = (String) wiz.getProperty(CommonDetectorInformationWizardPanel.PROP_NAME_DETECTOR_NAME);
detectorDescription = (String) wiz.getProperty(CommonDetectorInformationWizardPanel.PROP_NAME_DETECTOR_DESCRIPTION);
break;
case 1:
detectorTemplate = (Detector) wiz.getProperty(DetectorTemplateWizardPanel.PROP_NAME_TEMPLATE_INSTANCE);
break;
case 2:
trainingsMap = (Map<String, List<Node>>) wiz.getProperty(TrainingSetSelectionWizardPanel.PROP_NAME_TRAININGS_SET);
break;
case 3:
inferenceDataSet = (List<Node>) wiz.getProperty(InferenceDataSetSelectionWizardPanel.PROP_NAME_INFERENCE_DATA);
break;
default:
throw new AssertionError();
}
}
if (detectorName != null && detectorTemplate != null) {
try {
Detector detector = DetectorUtils.copyInstance(detectorTemplate);
DetectorDescriptor detectorDescriptor = detector.getDetectorDescriptor();
detectorDescriptor.setName(detectorName);
if (detectorDescription != null) {
detectorDescriptor.setDescription(detectorDescription);
}
// add trainings map values to the descriptor
addTrainingsSet(detectorDescriptor, trainingsMap);
// add inference set values to the descriptor
addInferenceDataset(detectorDescriptor, inferenceDataSet);
int lastIndexOf = detectorName.lastIndexOf(".");
detectorName = lastIndexOf > -1 ? detectorName.substring(0, lastIndexOf) : detectorName;
FileObject destFileObject = context.getPrimaryFile().createData(MessageFormat.format("{0}.dec", detectorName));
DetectorUtils.saveDetector(destFileObject, detectorDescriptor);
} catch (DetectorUtils.DetectorCopyException ex) {
Exceptions.printStackTrace(ex);
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
}
private void configurePanels(List<WizardDescriptor.Panel<WizardDescriptor>> panels) {
String[] steps = new String[panels.size()];
for (int i = 0; i < panels.size(); i++) {
Component c = panels.get(i).getComponent();
// Default step name to component name of panel.
steps[i] = c.getName();
if (c instanceof JComponent) {
// assume Swing components
JComponent jc = (JComponent) c;
jc.putClientProperty(WizardDescriptor.PROP_CONTENT_SELECTED_INDEX, i);
jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DATA, steps);
jc.putClientProperty(WizardDescriptor.PROP_AUTO_WIZARD_STYLE, true);
jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DISPLAYED, true);
jc.putClientProperty(WizardDescriptor.PROP_CONTENT_NUMBERED, true);
}
}
wiz.putProperty(WizardDescriptor.PROP_CONTENT_DATA, steps);
}
@SuppressWarnings("unchecked")
private List<WizardDescriptor.Panel<WizardDescriptor>> createPanels() {
if (panels == null) {
WizardDescriptor.Panel<WizardDescriptor> commonDetectorInformationWizardPanel = new CommonDetectorInformationWizardPanel();
WizardDescriptor.Panel<WizardDescriptor> inferenceModelSelectionWizardPanel = new InferenceModelSelectionWizardPanel();
WizardDescriptor.Panel<WizardDescriptor> inferenceModelFeatureSelectionWizardPanel = new InferenceModelFeatureSelectionWizardPanel();
WizardDescriptor.Panel<WizardDescriptor> preprocessorSelectionWizardPanel = new PreprocessorSelectionWizardPanel();
WizardDescriptor.Panel<WizardDescriptor> postprocessorSelectionWizardPanel = new PostprocessorSelectionWizardPanel();
WizardDescriptor.Panel<WizardDescriptor> trainingSetSelectionWizardPanel = new TrainingSetSelectionWizardPanel();
WizardDescriptor.Panel<WizardDescriptor> inferenceDataSetSelectionWizardPanel = new InferenceDataSetSelectionWizardPanel();
WizardDescriptor.Panel<WizardDescriptor> detectorTemplateWizardPanel = new DetectorTemplateWizardPanel();
withoutTemplatePanels = Arrays.asList(
commonDetectorInformationWizardPanel,
inferenceModelSelectionWizardPanel,
inferenceModelFeatureSelectionWizardPanel,
preprocessorSelectionWizardPanel,
postprocessorSelectionWizardPanel,
trainingSetSelectionWizardPanel,
inferenceDataSetSelectionWizardPanel);
viaTemplatePanels = Arrays.asList(
commonDetectorInformationWizardPanel,
detectorTemplateWizardPanel,
trainingSetSelectionWizardPanel,
inferenceDataSetSelectionWizardPanel);
// default panel array
panels = withoutTemplatePanels;
configurePanels(panels);
}
return panels;
}
@SuppressWarnings("unchecked")
private List<WizardDescriptor.Panel<WizardDescriptor>> getPanels() {
List<WizardDescriptor.Panel<WizardDescriptor>> currentPanels = createPanels();
if (index == 0) {
if (wiz.getProperty(PROP_NAME_CREATE_VIA_TEMPLATE) instanceof Boolean
&& (Boolean) wiz.getProperty(PROP_NAME_CREATE_VIA_TEMPLATE)) {
if (currentPanels != viaTemplatePanels) {
panels = viaTemplatePanels;
currentPanels = viaTemplatePanels;
configurePanels(currentPanels);
}
} else {
if (currentPanels != withoutTemplatePanels) {
panels = withoutTemplatePanels;
currentPanels = withoutTemplatePanels;
configurePanels(currentPanels);
}
}
}
return currentPanels;
}
@Override
public WizardDescriptor.Panel<WizardDescriptor> current() {
return getPanels().get(index);
}
@Override
public String name() {
return index + 1 + ". from " + getPanels().size();
}
@Override
public boolean hasNext() {
return index < getPanels().size() - 1;
}
@Override
public boolean hasPrevious() {
return index > 0;
}
@Override
public void nextPanel() {
if (!hasNext()) {
throw new NoSuchElementException();
}
index++;
}
@Override
public void previousPanel() {
if (!hasPrevious()) {
throw new NoSuchElementException();
}
index--;
}
// If nothing unusual changes in the middle of the wizard, simply:
@Override
public void addChangeListener(ChangeListener l) {
cs.addChangeListener(l);
}
// If something changes dynamically (besides moving between panels), e.g.
// the number of panels changes in response to user input, then use
// ChangeSupport to implement add/removeChangeListener and call fireChange
// when needed
@Override
public void removeChangeListener(ChangeListener l) {
cs.removeChangeListener(l);
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (PROP_NAME_CREATE_VIA_TEMPLATE.equals(evt.getPropertyName())) {
cs.fireChange();
}
}
}