package org.openlca.app.components; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.swt.custom.StackLayout; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.forms.widgets.FormToolkit; import org.openlca.app.M; import org.openlca.app.util.Colors; import org.openlca.app.util.Controls; import org.openlca.app.util.Error; import org.openlca.app.util.Labels; import org.openlca.app.util.UI; import org.openlca.core.math.NumberGenerator; import org.openlca.core.model.Uncertainty; import org.openlca.core.model.UncertaintyType; import org.openlca.expressions.FormulaInterpreter; import org.openlca.expressions.Scope; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** Dialog for editing uncertainty informations . */ public class UncertaintyDialog extends Dialog { private Logger log = LoggerFactory.getLogger(getClass()); private FormToolkit toolkit; private UncertaintyType[] types = UncertaintyType.values(); private Combo combo; private StackLayout stackLayout; private UncertaintyPanel[] clients; private UncertaintyPanel selectedClient; private Scope interpreterScope; private Uncertainty uncertainty; private double defaultMean; public UncertaintyDialog(Shell parentShell, Uncertainty initial) { super(parentShell); toolkit = new FormToolkit(parentShell.getDisplay()); if (initial == null) initial = new Uncertainty(); this.uncertainty = initial.clone(); if (uncertainty.getParameter1Value() != null) defaultMean = uncertainty.getParameter1Value(); } public Uncertainty getUncertainty() { return uncertainty; } public void setInterpreter(FormulaInterpreter interpreter, long scope) { if (!interpreter.hasScope(scope)) this.interpreterScope = interpreter.getGlobalScope(); else this.interpreterScope = interpreter.getScope(scope); } @Override protected void createButtonsForButtonBar(Composite parent) { toolkit.adapt(parent); createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); createButton(parent, IDialogConstants.HELP_ID, M.Test, false); createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); getShell().pack(); } @Override protected Point getInitialSize() { return new Point(450, 300); } @Override protected void okPressed() { uncertainty = selectedClient.fetchUncertainty(); super.okPressed(); } @Override protected void buttonPressed(int buttonId) { super.buttonPressed(buttonId); if (buttonId != IDialogConstants.HELP_ID) return; try { final NumberGenerator generator = makeGenerator(); UncertaintyShell.show(generator); } catch (Exception e) { log.error("failed to run uncertainty test"); } } private NumberGenerator makeGenerator() { Uncertainty uncertainty = selectedClient.fetchUncertainty(); switch (uncertainty.getDistributionType()) { case LOG_NORMAL: return NumberGenerator.logNormal(uncertainty.getParameter1Value(), uncertainty.getParameter2Value()); case NONE: return NumberGenerator.discrete(uncertainty.getParameter1Value()); case NORMAL: return NumberGenerator.normal(uncertainty.getParameter1Value(), uncertainty.getParameter2Value()); case TRIANGLE: return NumberGenerator.triangular(uncertainty.getParameter1Value(), uncertainty.getParameter2Value(), uncertainty.getParameter3Value()); case UNIFORM: return NumberGenerator.uniform(uncertainty.getParameter1Value(), uncertainty.getParameter2Value()); default: return NumberGenerator.discrete(1); } } @Override protected Control createDialogArea(Composite root) { getShell().setText(M.Uncertainty); toolkit.adapt(root); Composite area = (Composite) super.createDialogArea(root); toolkit.adapt(area); Composite container = toolkit.createComposite(area); UI.gridData(container, true, true); UI.gridLayout(container, 1); createCombo(container); createCompositeStack(container); initComposite(); getShell().pack(); UI.center(getParentShell(), getShell()); return area; } private void createCombo(Composite container) { Composite comboComposite = toolkit.createComposite(container); UI.gridData(comboComposite, true, false); UI.gridLayout(comboComposite, 2); combo = UI.formCombo(comboComposite, toolkit, M.UncertaintyDistribution); String[] items = new String[types.length]; int idx = 0; for (int i = 0; i < items.length; i++) { UncertaintyType type = types[i]; items[i] = Labels.uncertaintyType(type); if (uncertainty != null && uncertainty.getDistributionType() == type) idx = i; } combo.setItems(items); combo.select(idx); Controls.onSelect(combo, (e) -> initComposite()); } private void initComposite() { int item = combo.getSelectionIndex(); if (item == -1) return; selectedClient = clients[item]; stackLayout.topControl = selectedClient.composite; getShell().layout(true, true); getShell().pack(); } private void createCompositeStack(Composite container) { Composite stack = toolkit.createComposite(container); UI.gridData(stack, true, true); stackLayout = new StackLayout(); stack.setLayout(stackLayout); clients = new UncertaintyPanel[types.length]; for (int i = 0; i < types.length; i++) { Composite composite = toolkit.createComposite(stack); UI.gridLayout(composite, 2); UncertaintyPanel client = new UncertaintyPanel(composite, types[i]); clients[i] = client; } } @Override public boolean close() { if (toolkit != null) toolkit.dispose(); return super.close(); } private class UncertaintyPanel { private Composite composite; private Uncertainty _uncertainty; private Text[] texts; UncertaintyPanel(Composite composite, UncertaintyType type) { this.composite = composite; if (type == uncertainty.getDistributionType()) _uncertainty = uncertainty; else _uncertainty = createUncertainty(type); if (type != UncertaintyType.NONE) createTextFields(); else { Label label = toolkit.createLabel(composite, M.NoDistribution); label.setForeground(Colors.darkGray()); } } private void createTextFields() { String[] labels = getLabels(); texts = new Text[labels.length]; for (int param = 1; param <= 3; param++) { if (!hasParameter(param)) continue; String label = labels[param - 1]; Text text = UI.formText(composite, toolkit, label); text.setText(initialValue(param)); texts[param - 1] = text; } } private String initialValue(int param) { switch (param) { case 1: return initialValue(_uncertainty.getParameter1Value(), _uncertainty.getParameter1Formula()); case 2: return initialValue(_uncertainty.getParameter2Value(), _uncertainty.getParameter2Formula()); case 3: return initialValue(_uncertainty.getParameter3Value(), _uncertainty.getParameter3Formula()); default: return ""; } } private String initialValue(Double value, String formula) { if (formula != null && !formula.isEmpty()) return formula; if (value == null) return ""; else return Double.toString(value); } private String[] getLabels() { switch (_uncertainty.getDistributionType()) { case LOG_NORMAL: return new String[] { M.GeometricMean, M.GeometricStandardDeviation }; case NONE: return new String[0]; case NORMAL: return new String[] { M.Mean, M.StandardDeviation }; case TRIANGLE: return new String[] { M.Minimum, M.Mode, M.Maximum }; case UNIFORM: return new String[] { M.Minimum, M.Maximum }; default: return new String[0]; } } private Uncertainty createUncertainty(UncertaintyType type) { switch (type) { case LOG_NORMAL: return Uncertainty.logNormal(defaultMean, 1); case NONE: return Uncertainty.none(defaultMean); case NORMAL: return Uncertainty.normal(defaultMean, 1); case TRIANGLE: return Uncertainty.triangle(defaultMean, defaultMean, defaultMean); case UNIFORM: return Uncertainty.uniform(defaultMean, defaultMean); default: return null; } } private boolean hasParameter(int parameter) { switch (_uncertainty.getDistributionType()) { case LOG_NORMAL: return parameter == 1 || parameter == 2; case NONE: return false; case NORMAL: return parameter == 1 || parameter == 2; case TRIANGLE: return parameter == 1 || parameter == 2 || parameter == 3; case UNIFORM: return parameter == 1 || parameter == 2; default: return false; } } Uncertainty fetchUncertainty() { if (texts == null) return _uncertainty; for (int i = 0; i < texts.length; i++) { String s = texts[i].getText(); int param = i + 1; try { if (isValidNumber(s)) set(param, Double.parseDouble(s), null); else if (isValidFormula(s)) set(param, interpreterScope.eval(s), s); } catch (Exception e) { log.error("failed to set uncertainty value", e); } } return _uncertainty; } private void set(int param, double val, String s) { switch (param) { case 1: _uncertainty.setParameter1Formula(s); _uncertainty.setParameter1Value(val); break; case 2: _uncertainty.setParameter2Formula(s); _uncertainty.setParameter2Value(val); break; case 3: _uncertainty.setParameter3Formula(s); _uncertainty.setParameter3Value(val); break; default: break; } } private boolean isValidNumber(String s) { try { Double.parseDouble(s); return true; } catch (Exception e) { if (interpreterScope == null) Error.showBox(s + " " + M.IsNotValidNumber); return false; } } private boolean isValidFormula(String s) { if (interpreterScope == null) return false; try { interpreterScope.eval(s); return true; } catch (Exception e) { Error.showBox(M.FormulaEvaluationFailed + ": " + s); return false; } } } }