package org.openlca.app.editors.processes.data_quality; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Consumer; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; 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.eclipse.ui.forms.widgets.ScrolledForm; import org.openlca.app.M; import org.openlca.app.util.Colors; import org.openlca.app.util.Controls; import org.openlca.app.util.UI; import org.openlca.core.model.DQIndicator; import org.openlca.core.model.DQScore; import org.openlca.core.model.DQSystem; public class DataQualityShell extends Shell { private final FormToolkit toolkit = new FormToolkit(Display.getDefault()); private List<DataQualityCell> dataCells = new ArrayList<>(); private final DQSystem system; private final String dqEntry; private Text baseUncertaintyText; private Text valueLabel; public Consumer<DataQualityShell> onOk; public Consumer<DataQualityShell> onDelete; public Consumer<DataQualityShell> onUseUncertainties; public static DataQualityShell withoutUncertainty(Shell parent, DQSystem system, String dqEntry) { DataQualityShell shell = new DataQualityShell(parent, system, dqEntry); shell.create(false); shell.initSelection(null); return shell; } public static DataQualityShell withUncertainty(Shell parent, DQSystem system, String dqEntry, Double uncertainty) { DataQualityShell shell = new DataQualityShell(parent, system, dqEntry); shell.create(true); shell.initSelection(uncertainty); return shell; } private DataQualityShell(Shell parent, DQSystem system, String dqEntry) { super(parent, SWT.TITLE | SWT.RESIZE | SWT.CLOSE | SWT.APPLICATION_MODAL); this.system = system; this.dqEntry = dqEntry; setLayout(new FillLayout(SWT.HORIZONTAL)); setText(M.PedigreeMatrix); setSize(830, 750); UI.center(parent, this); } private void initSelection(Double baseUncertainty) { if (dqEntry == null) return; int[] values = system.toValues(dqEntry); if (values == null) return; for (int i = 1; i <= values.length; i++) { if (values[i - 1] == 0) continue; DQIndicator indicator = system.getIndicator(i); if (indicator == null) continue; DQScore score = indicator.getScore(values[i - 1]); if (score == null) continue; select(indicator, score); } if (!system.hasUncertainties) return; if (baseUncertainty == null) baseUncertainty = 1d; baseUncertaintyText.setText(Double.toString(baseUncertainty)); updateSigmaG(); } public String getSelection() { boolean anySelected = false; int[] values = new int[system.indicators.size()]; for (DQIndicator indicator : system.indicators) { DQScore selection = getSelection(indicator); int value = 0; if (selection != null) { value = selection.position; anySelected = true; } values[indicator.position - 1] = value; } if (!anySelected) return null; return system.toString(values); } private DQScore getSelection(DQIndicator indicator) { for (DataQualityCell cell : dataCells) if (cell.getIndicator() == indicator && cell.isSelected()) return cell.getScore(); return null; } private void create(boolean withUncertainty) { ScrolledForm form = toolkit.createScrolledForm(this); Composite root = form.getBody(); UI.gridLayout(root, 1); createHeader(root); createSeparator(root); createContent(root); createSeparator(root); createFooter(root, withUncertainty); } private void createContent(Composite root) { Composite composite = toolkit.createComposite(root); composite.setLayout(new GridLayout(system.getScoreCount() + 1, false)); UI.gridData(composite, true, true); createContentHeader(composite); createContentData(composite); } private void createContentHeader(Composite composite) { toolkit.createLabel(composite, ""); for (int i = 1; i <= system.getScoreCount(); i++) { Label label = toolkit.createLabel(composite, system.getScoreLabel(i)); label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false)); } } private void createContentData(Composite composite) { Collections.sort(system.indicators); for (DQIndicator indicator : system.indicators) { String rowText = indicator.name; Label rowLabel = toolkit.createLabel(composite, rowText, SWT.WRAP); GridData gridData = UI.gridData(rowLabel, false, true); gridData.widthHint = 120; gridData.minimumWidth = 120; createRowData(composite, indicator); } } private void createRowData(Composite composite, DQIndicator indicator) { Collections.sort(indicator.scores); for (DQScore score : indicator.scores) { DataQualityCell dataCell = new DataQualityCell(this, indicator, score); dataCell.createComponents(composite, toolkit); dataCells.add(dataCell); } } private void createHeader(Composite root) { Composite header = toolkit.createComposite(root); header.setLayout(new GridLayout(1, false)); UI.gridData(header, true, false); toolkit.paintBordersFor(header); toolkit.createLabel(header, M.PedigreeMatrixMessage); } private void createSeparator(Composite root) { Composite sep = toolkit.createCompositeSeparator(root); UI.gridData(sep, true, false).heightHint = 1; toolkit.paintBordersFor(sep); } private void createFooter(Composite root, boolean withUncertainty) { if (withUncertainty && system.hasUncertainties) { createUncertaintyFields(root); } createButtons(root); } private void createUncertaintyFields(Composite parent) { Composite composite = toolkit.createComposite(parent); UI.gridLayout(composite, 5); UI.gridData(composite, true, false); toolkit.paintBordersFor(composite); toolkit.createLabel(composite, M.BaseUncertainty + ": "); baseUncertaintyText = toolkit.createText(composite, "1.0"); UI.gridData(baseUncertaintyText, false, false).widthHint = 80; baseUncertaintyText.addModifyListener((e) -> updateSigmaG()); toolkit.createLabel(composite, "\u03c3g: "); valueLabel = toolkit.createText(composite, "", SWT.NONE); valueLabel.setEditable(false); UI.gridData(valueLabel, true, false); Button button = new Button(composite, SWT.NONE); button.setText("Use as uncertainty value"); Controls.onSelect(button, (e) -> onUseUncertainties.accept(this)); } private void createButtons(Composite parent) { Composite composite = toolkit.createComposite(parent); UI.gridLayout(composite, 3); GridData gd = UI.gridData(composite, true, false); gd.horizontalAlignment = SWT.END; toolkit.paintBordersFor(composite); Button okBtn = toolkit.createButton(composite, M.OK, SWT.NONE); UI.gridData(okBtn, false, false).widthHint = 60; okBtn.addSelectionListener(new DataQualityFinishHandler(this, (s) -> onOk.accept(s))); if (dqEntry != null) { Button deleteBtn = toolkit.createButton(composite, M.Delete, SWT.NONE); UI.gridData(deleteBtn, false, false).widthHint = 60; deleteBtn.addSelectionListener(new DataQualityFinishHandler(this, (s) -> onDelete.accept(s))); } Button cancelBtn = toolkit.createButton(composite, M.Cancel, SWT.NONE); cancelBtn.addSelectionListener(new DataQualityFinishHandler(this, null)); UI.gridData(cancelBtn, false, false).widthHint = 60; } public double updateSigmaG() { if (baseUncertaintyText == null) return 0; try { double sigma = calculateGeometricSD(); valueLabel.setText(Double.toString(sigma)); baseUncertaintyText.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE)); baseUncertaintyText.setToolTipText(null); return sigma; } catch (Exception e) { baseUncertaintyText.setBackground(Colors.errorColor()); baseUncertaintyText.setToolTipText(M.InvalidValue); return 0; } } private double calculateGeometricSD() { double varSum = 0; for (DQIndicator indicator : system.indicators) { DQScore selectedScore = getSelection(indicator); if (selectedScore == null) selectedScore = indicator.scores.get(indicator.scores.size() - 1); double factor = selectedScore.uncertainty; varSum += Math.pow(Math.log(factor), 2); } varSum += Math.pow(Math.log(getBaseValue()), 2); return Math.sqrt(Math.exp(Math.sqrt(varSum))); } public Double getBaseValue() { if (baseUncertaintyText == null) return null; String baseFactorText = baseUncertaintyText.getText(); try { return Double.parseDouble(baseFactorText); } catch (Exception e) { return Double.NaN; } } @Override protected void checkSubclass() { } void select(DQIndicator indicator, DQScore score) { for (DataQualityCell cell : dataCells) { if (cell.getIndicator() == indicator) { boolean selected = cell.getScore() == score; if (selected && cell.isSelected()) selected = false; cell.setSelected(selected); cell.setColor(); } } } }