package org.openlca.app.editors.projects;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.forms.widgets.Section;
import org.openlca.app.App;
import org.openlca.app.M;
import org.openlca.app.components.ModelSelectionDialog;
import org.openlca.app.db.Database;
import org.openlca.app.editors.InfoSection;
import org.openlca.app.editors.ModelPage;
import org.openlca.app.editors.reports.ReportViewer;
import org.openlca.app.editors.reports.Reports;
import org.openlca.app.editors.reports.model.ReportCalculator;
import org.openlca.app.preferencepages.FeatureFlag;
import org.openlca.app.rcp.images.Images;
import org.openlca.app.util.Actions;
import org.openlca.app.util.Controls;
import org.openlca.app.util.Editors;
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.ComboBoxCellModifier;
import org.openlca.app.viewers.table.modify.ModifySupport;
import org.openlca.app.viewers.table.modify.TextCellModifier;
import org.openlca.app.viewers.table.modify.field.DoubleModifier;
import org.openlca.core.database.IDatabase;
import org.openlca.core.database.ProductSystemDao;
import org.openlca.core.model.AllocationMethod;
import org.openlca.core.model.Exchange;
import org.openlca.core.model.FlowPropertyFactor;
import org.openlca.core.model.FlowType;
import org.openlca.core.model.ModelType;
import org.openlca.core.model.ParameterRedef;
import org.openlca.core.model.ProductSystem;
import org.openlca.core.model.Project;
import org.openlca.core.model.ProjectVariant;
import org.openlca.core.model.Unit;
import org.openlca.core.model.UnitGroup;
import org.openlca.core.model.descriptors.BaseDescriptor;
import org.openlca.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class ProjectSetupPage extends ModelPage<Project> {
private Logger log = LoggerFactory.getLogger(getClass());
private FormToolkit toolkit;
private ProjectEditor editor;
private IDatabase database = Database.get();
private Project project;
private TableViewer variantViewer;
private ProjectParameterTable parameterTable;
private ReportVariantSync variantSync;
private ScrolledForm form;
ProjectSetupPage(ProjectEditor editor) {
super(editor, "ProjectSetupPage", M.ProjectSetup);
this.editor = editor;
project = editor.getModel();
variantSync = new ReportVariantSync(editor);
editor.onSaved(() -> {
project = editor.getModel();
if (variantViewer != null)
variantViewer.setInput(project.getVariants());
});
}
@Override
protected void createFormContent(IManagedForm managedForm) {
form = UI.formHeader(managedForm);
updateFormTitle();
if (FeatureFlag.SHOW_REFRESH_BUTTONS.isEnabled())
Editors.addRefresh(form, editor);
toolkit = managedForm.getToolkit();
Composite body = UI.formBody(form, toolkit);
InfoSection infoSection = new InfoSection(getEditor());
infoSection.render(body, toolkit);
createButtons(infoSection.getContainer());
new ImpactSection(editor).render(body, toolkit);
createVariantsSection(body);
createParameterSection(body);
initialInput();
new ProcessContributionSection(editor).create(body, toolkit);
body.setFocus();
form.reflow(true);
}
@Override
protected void updateFormTitle() {
if (form == null)
return;
form.setText(M.Project + ": " + getModel().getName());
}
private void initialInput() {
List<ProjectVariant> variants = project.getVariants();
Collections.sort(variants,
(v1, v2) -> Strings.compare(v1.getName(), v2.getName()));
variantViewer.setInput(variants);
}
private void createButtons(Composite composite) {
toolkit.createLabel(composite, "");
Composite buttonContainer = toolkit.createComposite(composite);
UI.gridLayout(buttonContainer, 2).marginHeight = 5;
createReportButton(buttonContainer);
}
private void createReportButton(Composite composite) {
Button button = toolkit.createButton(composite, M.Report,
SWT.NONE);
UI.gridData(button, false, false).widthHint = 100;
button.setImage(Images.get(ModelType.PROJECT));
Controls.onSelect(button, (e) -> {
App.run(M.Calculate,
new ReportCalculator(getModel(), editor.getReport()),
() -> {
Reports.save(getModel(), editor.getReport(), database);
ReportViewer.open(editor.getReport());
});
});
}
private void createVariantsSection(Composite body) {
Section section = UI.section(body, toolkit, M.Variants);
Composite composite = UI.sectionClient(section, toolkit);
UI.gridLayout(composite, 1);
String[] properties = { M.Name, M.ProductSystem,
M.AllocationMethod, M.Flow, M.Amount,
M.Unit, M.Description };
variantViewer = Tables.createViewer(composite, properties);
variantViewer.setLabelProvider(new VariantLabelProvider());
Tables.bindColumnWidths(variantViewer, 0.15, 0.15, 0.15, 0.15, 0.125,
0.125, 0.15);
ModifySupport<ProjectVariant> support = new ModifySupport<>(
variantViewer);
support.bind(M.Name, new VariantNameEditor());
support.bind(M.AllocationMethod, new VariantAllocationEditor());
support.bind(M.Amount, new DoubleModifier<>(editor, "amount"));
support.bind(M.Unit, new VariantUnitEditor());
support.bind(M.Description, new VariantDescriptionEditor());
addVariantActions(variantViewer, section);
}
private void createParameterSection(Composite body) {
Section section = UI.section(body, toolkit, M.Parameters);
parameterTable = new ProjectParameterTable(editor);
parameterTable.render(section, toolkit);
}
private void addVariantActions(TableViewer viewer, Section section) {
Action add = Actions.onAdd(this::addVariant);
Action remove = Actions.onRemove(this::removeVariant);
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) {
addVariant();
return;
}
ProjectVariant variant = Viewers.getFirstSelected(viewer);
if (variant != null)
App.openEditor(variant.getProductSystem());
});
}
private void addVariant() {
log.trace("add variant");
BaseDescriptor d = ModelSelectionDialog
.select(ModelType.PRODUCT_SYSTEM);
if (d == null)
return;
ProductSystemDao dao = new ProductSystemDao(database);
ProductSystem system = dao.getForId(d.getId());
if (system == null) {
log.error("failed to load product system");
return;
}
List<ProjectVariant> variants = project.getVariants();
ProjectVariant variant = createVariant(system, variants.size() + 1);
variants.add(variant);
variantViewer.setInput(variants);
parameterTable.addVariant(variant);
variantSync.variantAdded(variant);
editor.setDirty(true);
}
private ProjectVariant createVariant(ProductSystem system, int i) {
ProjectVariant variant = new ProjectVariant();
variant.setProductSystem(system);
variant.setName(M.Variant + i);
variant.setAllocationMethod(AllocationMethod.NONE);
variant.setAmount(system.getTargetAmount());
variant.setFlowPropertyFactor(system.getTargetFlowPropertyFactor());
variant.setUnit(system.getTargetUnit());
for (ParameterRedef redef : system.getParameterRedefs())
variant.getParameterRedefs().add(redef.clone());
return variant;
}
private void removeVariant() {
log.trace("remove variant");
List<ProjectVariant> selection = Viewers.getAllSelected(variantViewer);
if (selection == null || selection.isEmpty())
return;
List<ProjectVariant> variants = project.getVariants();
for (ProjectVariant var : selection) {
variants.remove(var);
parameterTable.removeVariant(var);
}
variantViewer.setInput(variants);
variantSync.variantsRemoved(selection);
editor.setDirty(true);
}
private class VariantNameEditor extends TextCellModifier<ProjectVariant> {
@Override
protected String getText(ProjectVariant variant) {
return variant.getName();
}
@Override
protected void setText(ProjectVariant variant, String text) {
if (Objects.equals(text, variant.getName()))
return;
variantSync.updateName(variant, text);
variant.setName(text);
parameterTable.updateVariant(variant);
editor.setDirty(true);
}
}
private class VariantDescriptionEditor extends
TextCellModifier<ProjectVariant> {
@Override
protected String getText(ProjectVariant variant) {
return variantSync.getDescription(variant);
}
@Override
protected void setText(ProjectVariant variant, String text) {
String oldText = variantSync.getDescription(variant);
if (Objects.equals(text, oldText))
return;
variantSync.updateDescription(variant, text);
editor.setDirty(true);
}
}
private class VariantAllocationEditor extends
ComboBoxCellModifier<ProjectVariant, AllocationMethod> {
@Override
protected AllocationMethod getItem(ProjectVariant var) {
return var.getAllocationMethod() != null ? var
.getAllocationMethod() : AllocationMethod.NONE;
}
@Override
protected AllocationMethod[] getItems(ProjectVariant element) {
return AllocationMethod.values();
}
@Override
protected String getText(AllocationMethod value) {
return Labels.getEnumText(value);
}
@Override
protected void setItem(ProjectVariant var, AllocationMethod item) {
var.setAllocationMethod(item);
editor.setDirty(true);
}
}
private class VariantUnitEditor extends
ComboBoxCellModifier<ProjectVariant, Unit> {
@Override
protected Unit getItem(ProjectVariant var) {
return var.getUnit();
}
@Override
protected Unit[] getItems(ProjectVariant var) {
FlowPropertyFactor fac = var.getFlowPropertyFactor();
if (fac == null || fac.getFlowProperty() == null
|| fac.getFlowProperty().getUnitGroup() == null)
return new Unit[0];
UnitGroup unitGroup = fac.getFlowProperty().getUnitGroup();
Unit[] units = unitGroup.getUnits().toArray(
new Unit[unitGroup.getUnits().size()]);
Arrays.sort(units, (u1, u2) -> {
if (u1 == null || u2 == null)
return 0;
return Strings.compare(u1.getName(), u2.getName());
});
return units;
}
@Override
protected String getText(Unit unit) {
if (unit == null)
return "";
return unit.getName();
}
@Override
protected void setItem(ProjectVariant var, Unit unit) {
var.setUnit(unit);
editor.setDirty(true);
}
}
private class VariantLabelProvider extends LabelProvider implements
ITableLabelProvider {
@Override
public Image getColumnImage(Object element, int columnIndex) {
if (columnIndex == 1)
return Images.get(ModelType.PRODUCT_SYSTEM);
if (columnIndex == 3)
return Images.get(FlowType.PRODUCT_FLOW);
if (columnIndex == 5)
return Images.get(ModelType.UNIT);
return null;
}
@Override
public String getColumnText(Object element, int columnIndex) {
if (!(element instanceof ProjectVariant))
return null;
ProjectVariant variant = (ProjectVariant) element;
ProductSystem system = variant.getProductSystem();
if (system == null)
return null;
switch (columnIndex) {
case 0:
return variant.getName();
case 1:
return system.getName();
case 2:
return Labels.getEnumText(variant.getAllocationMethod());
case 3:
return getFlowText(system);
case 4:
return Double.toString(variant.getAmount());
case 5:
Unit unit = variant.getUnit();
return unit == null ? null : unit.getName();
case 6:
return variantSync.getDescription(variant);
default:
return null;
}
}
private String getFlowText(ProductSystem system) {
if (system == null || system.getReferenceExchange() == null)
return null;
Exchange refExchange = system.getReferenceExchange();
return Labels.getDisplayName(refExchange.getFlow());
}
}
}