package org.openlca.app.editors.projects; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.UUID; import org.eclipse.jface.action.Action; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Section; import org.openlca.app.M; import org.openlca.app.components.ParameterRedefDialog; import org.openlca.app.db.Cache; import org.openlca.app.util.Actions; import org.openlca.app.rcp.images.Images; import org.openlca.app.util.Labels; import org.openlca.app.util.UI; import org.openlca.app.util.tables.TableClipboard; import org.openlca.app.util.tables.Tables; import org.openlca.app.util.viewers.Viewers; import org.openlca.app.viewers.table.modify.ModifySupport; import org.openlca.app.viewers.table.modify.TextCellModifier; import org.openlca.core.database.EntityCache; import org.openlca.core.model.ModelType; import org.openlca.core.model.ParameterRedef; import org.openlca.core.model.Project; import org.openlca.core.model.ProjectVariant; import org.openlca.core.model.descriptors.BaseDescriptor; import org.openlca.core.model.descriptors.ImpactMethodDescriptor; import org.openlca.core.model.descriptors.ProcessDescriptor; import org.openlca.util.Strings; class ProjectParameterTable { private final int LABEL_COLS = 4; private final String PARAMETER = M.Parameter; private final String CONTEXT = M.Context; private final String NAME = M.ReportName; private final String DESCRIPTION = M.Description; private ProjectEditor editor; private ReportParameterSync reportSync; private EntityCache cache = Cache.getEntityCache(); private List<ParameterRedef> redefs = new ArrayList<>(); private Column[] columns; private TableViewer viewer; public ProjectParameterTable(ProjectEditor editor) { this.editor = editor; this.reportSync = new ReportParameterSync(editor); Project project = editor.getModel(); initColumns(project); initParameterRedefs(project); editor.onSaved(() -> updateOnSave(editor)); } private void updateOnSave(ProjectEditor editor) { Project newProject = editor.getModel(); for (ProjectVariant newVar : newProject.getVariants()) { for (Column col : columns) { if (equal(col.variant, newVar)) { col.variant = newVar; break; } } } } private void initColumns(Project project) { if (project == null) { columns = new Column[0]; return; } columns = new Column[project.getVariants().size()]; for (int i = 0; i < columns.length; i++) columns[i] = new Column(project.getVariants().get(i)); Arrays.sort(columns); } private void initParameterRedefs(Project project) { for (ProjectVariant variant : project.getVariants()) { for (ParameterRedef redef : variant.getParameterRedefs()) { if (!contains(redef)) redefs.add(redef); } } Collections.sort(redefs, (o1, o2) -> Strings.compare(o1.getName(), o2.getName())); } /** * true if a parameter redefinition with the given name and process ID (can * be null) exists. */ private boolean contains(ParameterRedef redef) { for (ParameterRedef contained : redefs) { if (Objects.equals(redef.getName(), contained.getName()) && Objects.equals(redef.getContextId(), contained.getContextId())) return true; } return false; } public void render(Section section, FormToolkit toolkit) { Composite composite = UI.sectionClient(section, toolkit); UI.gridLayout(composite, 1); viewer = Tables.createViewer(composite, getColumnTitles()); viewer.setLabelProvider(new LabelProvider()); Tables.bindColumnWidths(viewer, 0.15, 0.15, 0.15, 0.15); viewer.setInput(redefs); createModifySupport(); Action add = Actions.onAdd(this::onAdd); Action remove = Actions.onRemove(this::onRemove); Action copy = TableClipboard.onCopy(viewer); Actions.bind(section, add, remove); Actions.bind(viewer, add, remove, copy); Tables.onDoubleClick(viewer, (event) -> { TableItem item = Tables.getItem(viewer, event); if (item == null) onAdd(); }); } private String[] getColumnTitles() { String[] titles = new String[LABEL_COLS + columns.length]; titles[0] = PARAMETER; titles[1] = CONTEXT; titles[2] = NAME; titles[3] = DESCRIPTION; for (int i = 0; i < columns.length; i++) titles[i + LABEL_COLS] = columns[i].getTitle(); return titles; } private void createModifySupport() { // we use unique key to map the columns / editors to project variants String[] keys = new String[LABEL_COLS + columns.length]; keys[0] = PARAMETER; keys[1] = CONTEXT; keys[2] = NAME; keys[3] = DESCRIPTION; for (int i = 0; i < columns.length; i++) keys[i + LABEL_COLS] = columns[i].getKey(); viewer.setColumnProperties(keys); ModifySupport<ParameterRedef> modifySupport = new ModifySupport<>( viewer); modifySupport.bind(NAME, new NameModifier()); modifySupport.bind(DESCRIPTION, new DescriptionModifier()); for (int i = LABEL_COLS; i < keys.length; i++) modifySupport.bind(keys[i], new ValueModifier(keys[i])); } private void onAdd() { Set<Long> contexts = getParameterContexts(); List<ParameterRedef> redefs = ParameterRedefDialog.select(contexts); for (ParameterRedef redef : redefs) { if (contains(redef)) continue; this.redefs.add(redef); reportSync.parameterAdded(redef); for (Column column : columns) { if (findVariantRedef(column.variant, redef) == null) column.variant.getParameterRedefs().add(redef.clone()); } } viewer.setInput(this.redefs); editor.setDirty(true); } private Set<Long> getParameterContexts() { Project project = editor.getModel(); HashSet<Long> contexts = new HashSet<>(); if (project.getImpactMethodId() != null) contexts.add(project.getImpactMethodId()); for (ProjectVariant variant : project.getVariants()) { if (variant.getProductSystem() == null) continue; contexts.addAll(variant.getProductSystem().getProcesses()); } return contexts; } private void onRemove() { List<ParameterRedef> selection = Viewers.getAllSelected(viewer); for (ParameterRedef selected : selection) { this.redefs.remove(selected); reportSync.parameterRemoved(selected); for (Column column : columns) { ProjectVariant variant = column.variant; ParameterRedef redef = findVariantRedef(variant, selected); if (redef != null) variant.getParameterRedefs().remove(redef); } } viewer.setInput(this.redefs); editor.setDirty(true); } public void addVariant(ProjectVariant variant) { Column newColumn = new Column(variant); Table table = viewer.getTable(); TableColumn tableColumn = new TableColumn(table, SWT.NONE); tableColumn.setWidth(150); tableColumn.setText(newColumn.getTitle()); Column[] newColumns = new Column[columns.length + 1]; System.arraycopy(columns, 0, newColumns, 0, columns.length); newColumns[columns.length] = newColumn; columns = newColumns; createModifySupport(); viewer.refresh(); } public void removeVariant(ProjectVariant variant) { int idx = getIndex(variant); if (idx == -1) return; Column[] newColumns = new Column[columns.length - 1]; System.arraycopy(columns, 0, newColumns, 0, idx); if ((idx + 1) < columns.length) System.arraycopy(columns, idx + 1, newColumns, idx, newColumns.length - idx); columns = newColumns; Table table = viewer.getTable(); table.getColumn(idx + LABEL_COLS).dispose(); createModifySupport(); viewer.refresh(); } public void updateVariant(ProjectVariant variant) { int idx = getIndex(variant); if (idx == -1) return; Column column = columns[idx]; Table table = viewer.getTable(); String title = column.getTitle() == null ? "" : column.getTitle(); table.getColumn(idx + LABEL_COLS).setText(title); viewer.refresh(); } private ParameterRedef findVariantRedef(ProjectVariant variant, ParameterRedef redef) { if (variant == null) return null; for (ParameterRedef variantRedef : variant.getParameterRedefs()) { if (Objects.equals(variantRedef.getName(), redef.getName()) && Objects.equals(variantRedef.getContextId(), redef.getContextId())) return variantRedef; } return null; } private ProjectVariant findVariant(String key) { for (Column column : columns) { if (Objects.equals(key, column.getKey())) return column.getVariant(); } return null; } private int getIndex(ProjectVariant variant) { for (int i = 0; i < columns.length; i++) { if (equal(variant, columns[i].getVariant())) return i; } return -1; } private boolean equal(ProjectVariant var1, ProjectVariant var2) { // saving the project changes the ID of an unsaved variant and thus the // equal function of the ProjectVariant class will fail -> thus, we // check the name in this case. if (var1 == var2) return true; if (var1 == null || var2 == null) return false; if (var1.getId() != 0 && var2.getId() != 0) return var1.getId() == var2.getId(); else return Objects.equals(var1.getName(), var2.getName()); } private class LabelProvider extends org.eclipse.jface.viewers.LabelProvider implements ITableLabelProvider { @Override public Image getColumnImage(Object element, int columnIndex) { if (columnIndex != 0) return null; if (!(element instanceof ParameterRedef)) return null; ParameterRedef redef = (ParameterRedef) element; BaseDescriptor model = getModel(redef); if (model == null) return Images.get(ModelType.PARAMETER); else return Images.get(model); } @Override public String getColumnText(Object element, int col) { if (!(element instanceof ParameterRedef)) return null; ParameterRedef redef = (ParameterRedef) element; if (col == 0) return redef.getName(); if (col == 1) return getModelColumnText(redef); if (col == 2) return reportSync.getName(redef); if (col == 3) return reportSync.getDescription(redef); else return getVariantValue(col, redef); } private String getVariantValue(int col, ParameterRedef redef) { int idx = col - LABEL_COLS; if (idx < 0 || idx >= columns.length) return null; ProjectVariant variant = columns[idx].getVariant(); ParameterRedef variantRedef = findVariantRedef(variant, redef); if (variantRedef == null) return null; return Double.toString(variantRedef.getValue()); } private String getModelColumnText(ParameterRedef redef) { BaseDescriptor model = getModel(redef); if (model == null) return "global"; else return Labels.getDisplayName(model); } private BaseDescriptor getModel(ParameterRedef redef) { if (redef == null || redef.getContextId() == null) return null; long modelId = redef.getContextId(); BaseDescriptor model = cache.get(ImpactMethodDescriptor.class, modelId); if (model != null) return model; else return cache.get(ProcessDescriptor.class, modelId); } } private class ValueModifier extends TextCellModifier<ParameterRedef> { private String key; public ValueModifier(String key) { this.key = key; } protected String getText(ParameterRedef redef) { ProjectVariant variant = findVariant(key); ParameterRedef variantRedef = findVariantRedef(variant, redef); if (variantRedef == null) return ""; return Double.toString(variantRedef.getValue()); } @Override protected void setText(ParameterRedef redef, String text) { if (redef == null || text == null) return; ProjectVariant variant = findVariant(key); if (variant == null) return; ParameterRedef variantRedef = findVariantRedef(variant, redef); if (variantRedef == null) { variantRedef = redef.clone(); variant.getParameterRedefs().add(variantRedef); } try { double d = Double.parseDouble(text); variantRedef.setValue(d); reportSync.valueChanged(redef, variant, d); editor.setDirty(true); } catch (Exception e) { org.openlca.app.util.Error.showBox(M.InvalidNumber, text + " " + M.IsNotValidNumber); } } } private class NameModifier extends TextCellModifier<ParameterRedef> { @Override protected String getText(ParameterRedef redef) { return reportSync.getName(redef); } @Override protected void setText(ParameterRedef redef, String text) { String oldName = reportSync.getName(redef); if (Objects.equals(oldName, text)) return; reportSync.setName(text, redef); editor.setDirty(true); } } private class DescriptionModifier extends TextCellModifier<ParameterRedef> { @Override protected String getText(ParameterRedef redef) { return reportSync.getDescription(redef); } @Override protected void setText(ParameterRedef redef, String text) { String oldText = reportSync.getDescription(redef); if (Objects.equals(oldText, text)) return; reportSync.setDescription(text, redef); editor.setDirty(true); } } private class Column implements Comparable<Column> { private ProjectVariant variant; private String key; public Column(ProjectVariant variant) { this.variant = variant; key = UUID.randomUUID().toString(); } public ProjectVariant getVariant() { return variant; } public String getKey() { return key; } public String getTitle() { if (variant == null) return ""; return variant.getName(); } @Override public int compareTo(Column other) { if (this.variant == null || other.variant == null) return 0; return Strings.compare(this.variant.getName(), other.variant.getName()); } } }