/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.components.optimizer.gui.properties;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import de.rcenvironment.components.optimizer.common.MethodDescription;
import de.rcenvironment.components.optimizer.common.OptimizerComponentConstants;
import de.rcenvironment.components.optimizer.common.OptimizerFileLoader;
import de.rcenvironment.core.component.api.LoopComponentConstants;
import de.rcenvironment.core.component.workflow.model.api.WorkflowNode;
import de.rcenvironment.core.gui.utils.common.components.PropertyTabGuiHelper;
import de.rcenvironment.core.gui.workflow.editor.properties.ValidatingWorkflowNodePropertySection;
import de.rcenvironment.core.utils.common.JsonUtils;
/**
* "Properties" view tab for choosing Algorithm.
*
* @author Sascha Zur
*/
public abstract class AlgorithmSection extends ValidatingWorkflowNodePropertySection {
/**
* Red for warning color.
*/
public static final int RED = 232;
/**
* Blue for warning color.
*/
public static final int BLUE = 170;
private static final String COMMA = ",";
/**
* Selections.
*/
private static final String COULD_NOT_PARSE_METHOD_FILE = "Could not parse method file";
private Combo comboMainAlgorithmSelection;
private final ObjectMapper mapper = JsonUtils.getDefaultObjectMapper();
private Map<String, MethodDescription> methodDescriptions;
private Combo comboSecondAlgorithmSelection;
private Combo comboThirdAlgorithmSelection;
private Composite firstAlgo;
private Composite secondAlgo;
private Composite thirdAlgo;
private String[] methods;
private Label pythonLabel;
private Button dakotaPathButton;
public AlgorithmSection() {
try {
methodDescriptions = OptimizerFileLoader.getAllMethodDescriptions(getAlgorithmFolder());
} catch (JsonParseException e) {
logger.error("Could not parse method file ", e);
} catch (JsonMappingException e) {
logger.error("Could not map method file ", e);
} catch (IOException e) {
logger.error("Could not load method file ", e);
}
}
protected abstract String getAlgorithmFolder();
@Override
public void createCompositeContent(final Composite parent, final TabbedPropertySheetPage tabbedPropertySheetPage) {
super.createCompositeContent(parent, tabbedPropertySheetPage);
final Section sectionAlgorithm = PropertyTabGuiHelper.createSingleColumnSectionComposite(parent, getWidgetFactory(),
Messages.algorithm);
final Composite algorithmConfigurationParent = getWidgetFactory().createComposite(sectionAlgorithm);
sectionAlgorithm.setClient(algorithmConfigurationParent);
algorithmConfigurationParent.setLayout(new GridLayout(1, false));
methods = new String[methodDescriptions.keySet().size()];
methodDescriptions.keySet().toArray(methods);
Arrays.sort(methods);
firstAlgo = new Composite(algorithmConfigurationParent, SWT.NONE);
firstAlgo.setLayout(new GridLayout(2, false));
new Label(firstAlgo, SWT.NONE).setText("Main algorithm");
new Label(firstAlgo, SWT.NONE);
comboMainAlgorithmSelection = new Combo(firstAlgo, SWT.BORDER | SWT.READ_ONLY);
comboMainAlgorithmSelection.setItems(methods);
comboMainAlgorithmSelection.addListener(SWT.Selection, new SelectAlgorithmListener());
Button buttonProperties = new Button(firstAlgo, SWT.PUSH);
buttonProperties.setText(Messages.algorithmProperties);
SelectionAdapter buttonListener = new MethodSelectionAdapter(parent, comboMainAlgorithmSelection);
buttonProperties.addSelectionListener(buttonListener);
secondAlgo = new Composite(algorithmConfigurationParent, SWT.NONE);
secondAlgo.setLayout(new GridLayout(2, false));
secondAlgo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
new Label(secondAlgo, SWT.NONE).setText("Second algorithm");
new Label(secondAlgo, SWT.NONE);
comboSecondAlgorithmSelection = new Combo(secondAlgo, SWT.BORDER | SWT.READ_ONLY);
comboSecondAlgorithmSelection.setItems(methods);
comboSecondAlgorithmSelection.addListener(SWT.Selection, new SelectAlgorithmListener());
Button buttonSecondProperties = new Button(secondAlgo, SWT.PUSH);
buttonSecondProperties.setText(Messages.algorithmProperties);
SelectionAdapter buttonListenerSecond = new MethodSelectionAdapter(parent, comboSecondAlgorithmSelection);
buttonSecondProperties.addSelectionListener(buttonListenerSecond);
secondAlgo.setVisible(false);
thirdAlgo = new Composite(algorithmConfigurationParent, SWT.NONE);
thirdAlgo.setLayout(new GridLayout(2, false));
new Label(thirdAlgo, SWT.NONE).setText("Third algorithm");
new Label(thirdAlgo, SWT.NONE);
comboThirdAlgorithmSelection = new Combo(thirdAlgo, SWT.BORDER | SWT.READ_ONLY);
comboThirdAlgorithmSelection.setItems(methods);
comboThirdAlgorithmSelection.addListener(SWT.Selection, new SelectAlgorithmListener());
Button buttonThirdProperties = new Button(thirdAlgo, SWT.PUSH);
buttonThirdProperties.setText(Messages.algorithmProperties);
SelectionAdapter buttonListenerThird = new MethodSelectionAdapter(parent, comboThirdAlgorithmSelection);
buttonThirdProperties.addSelectionListener(buttonListenerThird);
thirdAlgo.setVisible(false);
pythonLabel = new Label(firstAlgo, SWT.NONE);
pythonLabel.setText(Messages.pythonForMethodInstalled);
GridData labelData = new GridData();
labelData.horizontalSpan = 2;
pythonLabel.setLayoutData(labelData);
dakotaPathButton = new Button(firstAlgo, SWT.CHECK);
dakotaPathButton.setText("Use custom dakota binary (selected at workflow start)");
dakotaPathButton.setData(CONTROL_PROPERTY_KEY, OptimizerComponentConstants.USE_CUSTOM_DAKOTA_PATH);
GridData pathData = new GridData();
pathData.horizontalSpan = 2;
dakotaPathButton.setLayoutData(pathData);
// useRestartFileButton = new Button(firstAlgo, SWT.CHECK);
// useRestartFileButton.setText("Use precalculated values for optimization (select file at workflow start)");
// useRestartFileButton.setData(CONTROL_PROPERTY_KEY, OptimizerComponentConstants.USE_RESTART_FILE);
sectionAlgorithm.addPaintListener(new PaintListener() {
@Override
public void paintControl(PaintEvent arg0) {
refreshSection();
}
});
}
@Override
public void aboutToBeShown() {
super.aboutToBeShown();
String configString = getConfiguration().getConfigurationDescription()
.getConfigurationValue(OptimizerComponentConstants.METHODCONFIGURATIONS);
Map<String, MethodDescription> allConfiguredDescriptions = null;
if (configString == null || configString.isEmpty()) {
try {
allConfiguredDescriptions = OptimizerFileLoader.getAllMethodDescriptions(getAlgorithmFolder());
if (allConfiguredDescriptions != null) {
setProperty(OptimizerComponentConstants.METHODCONFIGURATIONS,
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(allConfiguredDescriptions));
}
} catch (JsonParseException e) {
logger.error(e);
} catch (JsonMappingException e) {
logger.error(e);
} catch (IOException e) {
logger.error(e);
}
}
}
@SuppressWarnings("deprecation")
@Override
public void refreshSection() {
super.refreshSection();
aboutToBeShown();
String algorithm =
getConfiguration().getConfigurationDescription()
.getConfigurationValue(OptimizerComponentConstants.ALGORITHMS);
// LHS is not a optimizer method but a DoE. Although it is needed for the Surrogate Based
// optimizer method
if (comboMainAlgorithmSelection != null
&& Arrays.asList(comboMainAlgorithmSelection.getItems()).contains(OptimizerComponentConstants.DAKOTA_LHS)
&& !getAlgorithmFolder().equals("/doe")) {
comboMainAlgorithmSelection.remove(OptimizerComponentConstants.DAKOTA_LHS);
}
if (algorithm != null) {
final String[] selectedAlgorithm = getConfiguration().getConfigurationDescription()
.getConfigurationValue(OptimizerComponentConstants.ALGORITHMS).split(COMMA);
if (selectedAlgorithm != null && selectedAlgorithm.length > 0 && selectedAlgorithm[0] != null) {
boolean ok = false;
for (String str : comboMainAlgorithmSelection.getItems()) {
if (str.equals(selectedAlgorithm[0])) {
comboMainAlgorithmSelection.select(comboMainAlgorithmSelection.indexOf(selectedAlgorithm[0]));
ok = true;
}
}
if (!ok) {
comboMainAlgorithmSelection.clearSelection();
setProperty(OptimizerComponentConstants.ALGORITHMS, "");
}
}
refreshShownAlgorithms();
if (secondAlgo.isVisible() && selectedAlgorithm != null && selectedAlgorithm.length > 1 && selectedAlgorithm[1] != null) {
boolean ok = false;
for (String str : comboSecondAlgorithmSelection.getItems()) {
if (str.equals(selectedAlgorithm[1])) {
comboSecondAlgorithmSelection.select(comboSecondAlgorithmSelection.indexOf(selectedAlgorithm[1]));
ok = true;
}
}
if (!ok) {
comboSecondAlgorithmSelection.select(0);
}
}
if (thirdAlgo.isVisible() && selectedAlgorithm != null && selectedAlgorithm.length > 2 && selectedAlgorithm[2] != null) {
boolean ok = false;
for (String str : comboThirdAlgorithmSelection.getItems()) {
if (str.equals(selectedAlgorithm[2])) {
comboThirdAlgorithmSelection.select(comboThirdAlgorithmSelection.indexOf(selectedAlgorithm[2]));
ok = true;
}
}
if (!ok) {
comboThirdAlgorithmSelection.select(0);
}
}
String configString = getConfiguration().getConfigurationDescription()
.getConfigurationValue(OptimizerComponentConstants.METHODCONFIGURATIONS);
if (configString == null || configString.equals("")) {
try {
setProperty(OptimizerComponentConstants.METHODCONFIGURATIONS,
mapper.defaultPrettyPrintingWriter().writeValueAsString(methodDescriptions));
} catch (JsonParseException e) {
logger.error(COULD_NOT_PARSE_METHOD_FILE, e);
} catch (JsonMappingException e) {
logger.error(COULD_NOT_PARSE_METHOD_FILE, e);
} catch (IOException e) {
logger.error(COULD_NOT_PARSE_METHOD_FILE, e);
}
}
} else {
secondAlgo.setVisible(false);
thirdAlgo.setVisible(false);
comboMainAlgorithmSelection.setText("");
}
}
private void refreshShownAlgorithms() {
try {
String configString = getConfiguration().getConfigurationDescription()
.getConfigurationValue(OptimizerComponentConstants.METHODCONFIGURATIONS);
comboMainAlgorithmSelection.setText("");
@SuppressWarnings("unchecked") Map<String, MethodDescription> allConfiguredDescriptions =
mapper.readValue(configString, new HashMap<String, MethodDescription>().getClass());
MethodDescription mainAlgorithm = mapper.convertValue(
allConfiguredDescriptions.get(comboMainAlgorithmSelection.getText()), MethodDescription.class);
if (mainAlgorithm != null && mainAlgorithm.getOptimizerPackage() != null) {
pythonLabel.setVisible(true);
if (mainAlgorithm.getOptimizerPackage().equalsIgnoreCase("dakota")) {
pythonLabel.setText(Messages.dakotaOSHint);
dakotaPathButton.setVisible(true);
} else {
dakotaPathButton.setVisible(false);
pythonLabel.setText(Messages.pythonForMethodInstalled);
}
pythonLabel.getParent().pack();
if (mainAlgorithm.getOptimizerPackage().equals("dakota")
&& mainAlgorithm.getMethodName().contains(OptimizerComponentConstants.DAKOTA_SGB)) {
comboSecondAlgorithmSelection.removeAll();
comboThirdAlgorithmSelection.removeAll();
// if SGB is chosen, only Dakota LHS is available for the second algorithm
comboSecondAlgorithmSelection.add(OptimizerComponentConstants.DAKOTA_LHS);
comboThirdAlgorithmSelection.setItems(
mainAlgorithm.getSpecificSettings().get(OptimizerComponentConstants.APPROX_METHOD_KEY)
.get(OptimizerComponentConstants.DEFAULT_VALUE_KEY).split(COMMA));
secondAlgo.setVisible(true);
thirdAlgo.setVisible(true);
comboSecondAlgorithmSelection.select(comboSecondAlgorithmSelection.indexOf(OptimizerComponentConstants.DAKOTA_LHS));
comboThirdAlgorithmSelection.select(0);
} else {
if (mainAlgorithm.getFollowingMethods() != null && mainAlgorithm.getFollowingMethods().equals("1")) {
comboSecondAlgorithmSelection.removeAll();
filterMethodsList(mainAlgorithm, comboSecondAlgorithmSelection);
secondAlgo.setVisible(true);
thirdAlgo.setVisible(false);
comboSecondAlgorithmSelection.select(0);
} else if (mainAlgorithm.getFollowingMethods() != null && mainAlgorithm.getFollowingMethods().equals("2")) {
comboSecondAlgorithmSelection.removeAll();
comboThirdAlgorithmSelection.removeAll();
filterMethodsList(mainAlgorithm, comboSecondAlgorithmSelection);
filterMethodsList(mainAlgorithm, comboThirdAlgorithmSelection);
secondAlgo.setVisible(true);
thirdAlgo.setVisible(true);
comboSecondAlgorithmSelection.select(0);
comboThirdAlgorithmSelection.select(0);
} else {
secondAlgo.setVisible(false);
thirdAlgo.setVisible(false);
}
}
} else {
comboMainAlgorithmSelection.setText("");
pythonLabel.setVisible(false);
}
} catch (JsonParseException e1) {
logger.error(COULD_NOT_PARSE_METHOD_FILE, e1);
} catch (JsonMappingException e1) {
logger.error(COULD_NOT_PARSE_METHOD_FILE, e1);
} catch (IOException e1) {
logger.error(COULD_NOT_PARSE_METHOD_FILE, e1);
}
}
private void filterMethodsList(MethodDescription mainAlgorithm, Combo combo) {
List<String> result = new LinkedList<String>();
result.add("");
for (String currentAlgorithm : methodDescriptions.keySet()) {
if (methodDescriptions.get(currentAlgorithm).getOptimizerPackage().equalsIgnoreCase(mainAlgorithm.getOptimizerPackage())
&& !currentAlgorithm.equalsIgnoreCase(mainAlgorithm.getMethodName())) {
result.add(currentAlgorithm);
}
}
String[] methodList = new String[result.size()];
result.toArray(methodList);
Arrays.sort(methodList);
combo.setItems(methodList);
}
/**
* Selectionadapter for the dakota algorithms.
*
* @author Sascha Zur
*/
private class MethodSelectionAdapter extends SelectionAdapter {
private final Composite parent;
private final Combo attachedCombo;
MethodSelectionAdapter(Composite parent, Combo attachedCombo) {
this.parent = parent;
this.attachedCombo = attachedCombo;
}
@Override
@SuppressWarnings("unchecked")
public void widgetSelected(SelectionEvent e) {
String configString = getConfiguration().getConfigurationDescription()
.getConfigurationValue(OptimizerComponentConstants.METHODCONFIGURATIONS);
try {
Map<String, MethodDescription> allConfiguredDescriptions = null;
if (configString == null || configString.isEmpty()) {
allConfiguredDescriptions = OptimizerFileLoader.getAllMethodDescriptions(getAlgorithmFolder());
} else {
allConfiguredDescriptions = mapper.readValue(configString, new HashMap<String, MethodDescription>().getClass());
}
// Because the ObjectMapper doesn't create the MethodDescription objects but
// HashMaps in the previous step,
// the description to manipulate must be converted into the correct class.
if (allConfiguredDescriptions != null) {
allConfiguredDescriptions.put(attachedCombo.getText(),
mapper.convertValue(allConfiguredDescriptions.get(attachedCombo.getText()), MethodDescription.class));
if (attachedCombo.getText().equals("")) {
MessageBox dialog =
new MessageBox(parent.getShell(), SWT.ICON_WARNING | SWT.OK);
dialog.setText("No Algorithm");
dialog.setMessage("No algorithm selected!");
dialog.open();
} else {
MethodPropertiesDialogGenerator dialog = new MethodPropertiesDialogGenerator(
parent.getShell(), allConfiguredDescriptions.get(attachedCombo.getText()));
if (dialog.open() == Dialog.OK) {
setProperty(OptimizerComponentConstants.METHODCONFIGURATIONS,
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(allConfiguredDescriptions));
}
}
}
} catch (JsonParseException e1) {
logger.error(COULD_NOT_PARSE_METHOD_FILE, e1);
} catch (JsonMappingException e1) {
logger.error("Could not map method file", e1);
} catch (IOException e1) {
logger.error("Could not load method file", e1);
}
}
}
@Override
protected void setWorkflowNode(WorkflowNode workflowNode) {
super.setWorkflowNode(workflowNode);
addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().contains(LoopComponentConstants.CONFIG_KEY_IS_NESTED_LOOP)) {
if (Boolean.parseBoolean((String) evt.getNewValue())) {
setProperty(OptimizerComponentConstants.USE_RESTART_FILE, String.valueOf(false));
}
}
}
});
}
/**
* Listener for the Algorithm Combobox.
*
* @author Sascha Zur
*/
private class SelectAlgorithmListener implements Listener {
@SuppressWarnings("unchecked")
@Override
public void handleEvent(final Event event) {
String key = comboMainAlgorithmSelection.getItem(comboMainAlgorithmSelection.getSelectionIndex());
if (event.widget.equals(comboMainAlgorithmSelection)) {
refreshShownAlgorithms();
String configString = getConfiguration().getConfigurationDescription()
.getConfigurationValue(OptimizerComponentConstants.METHODCONFIGURATIONS);
try {
Map<String, MethodDescription> allConfiguredDescriptions = null;
if (configString == null || configString.isEmpty()) {
allConfiguredDescriptions = OptimizerFileLoader.getAllMethodDescriptions(getAlgorithmFolder());
} else {
allConfiguredDescriptions = mapper.readValue(configString, new HashMap<String, MethodDescription>().getClass());
}
if (!allConfiguredDescriptions.containsKey(key)) {
MethodDescription desc = OptimizerFileLoader.loadMethod(key);
if (desc != null) {
allConfiguredDescriptions.put(key, desc);
setProperty(OptimizerComponentConstants.METHODCONFIGURATIONS,
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(allConfiguredDescriptions));
}
}
} catch (JsonParseException e1) {
logger.error(COULD_NOT_PARSE_METHOD_FILE, e1);
} catch (JsonMappingException e1) {
logger.error("Could not map method file", e1);
} catch (IOException e1) {
logger.error("Could not load method file", e1);
}
}
if (secondAlgo.isVisible() && comboSecondAlgorithmSelection.getSelectionIndex() >= 0
&& !comboSecondAlgorithmSelection.getItem(comboSecondAlgorithmSelection.getSelectionIndex()).equals("")) {
key += COMMA + comboSecondAlgorithmSelection.getItem(comboSecondAlgorithmSelection.getSelectionIndex());
}
if (thirdAlgo.isVisible() && comboThirdAlgorithmSelection.getSelectionIndex() >= 0) {
key += COMMA + comboThirdAlgorithmSelection.getItem(comboThirdAlgorithmSelection.getSelectionIndex());
}
setProperty(OptimizerComponentConstants.ALGORITHMS, key);
setProperty(OptimizerComponentConstants.OPTIMIZER_PACKAGE,
methodDescriptions.get(comboMainAlgorithmSelection.getText()).getOptimizerPackage());
}
}
}