Skip to content

Commit

Permalink
[3826] Make EMF default form support attributes with a date
Browse files Browse the repository at this point in the history
It supports EAttribute with EDataType with class java.time.Instant and java.time.LocalDate

Bug: eclipse-sirius#3826
Signed-off-by: Laurent Fasani <[email protected]>
  • Loading branch information
lfasani authored and sbegaudeau committed Oct 11, 2024
1 parent 5701515 commit debe92a
Show file tree
Hide file tree
Showing 5 changed files with 357 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ This will allow specifier to create images that fir perfectly in the project tem
- https://github.com/eclipse-sirius/sirius-web/issues/4029[#4029] [sirius-web] Add Project Custom Images element to the exported APIs
- https://github.com/eclipse-sirius/sirius-web/issues/4027[#4027] [forms] List widgets in read-only mode now still allow the selection of their items, but still prevent the invocation of the corresponding single or double-click handlers (which can perform mutations).
- https://github.com/eclipse-sirius/sirius-web/issues/3816[#3816] [form] Make EMF default form support Integer null value
- https://github.com/eclipse-sirius/sirius-web/issues/3826[#3826] [form] Make EMF default form support attributes with a date


== v2024.9.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ private GroupDescription getGroupDescription() {
ifDescriptions.add(new EEnumIfDescriptionProvider(this.composedAdapterFactory, this.propertiesValidationProvider, this.semanticTargetIdProvider).getIfDescription());

ifDescriptions.add(new NonContainmentReferenceIfDescriptionProvider(this.composedAdapterFactory, this.objectService, this.emfKindService, this.feedbackMessageService, this.propertiesValidationProvider, this.semanticTargetIdProvider).getIfDescription());
ifDescriptions.add(new InstantIfDescriptionProvider(this.composedAdapterFactory, this.propertiesValidationProvider, this.semanticTargetIdProvider).getIfDescription());
ifDescriptions.add(new LocalDateIfDescriptionProvider(this.composedAdapterFactory, this.propertiesValidationProvider, this.semanticTargetIdProvider).getIfDescription());

var numericDataTypes = List.of(
EcorePackage.Literals.EINT,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*******************************************************************************
* Copyright (c) 2024 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.components.emf.forms;

import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;

import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.sirius.components.emf.forms.api.IPropertiesValidationProvider;
import org.eclipse.sirius.components.forms.DateTimeType;
import org.eclipse.sirius.components.forms.WidgetIdProvider;
import org.eclipse.sirius.components.forms.description.DateTimeDescription;
import org.eclipse.sirius.components.forms.description.IfDescription;
import org.eclipse.sirius.components.representations.Failure;
import org.eclipse.sirius.components.representations.IStatus;
import org.eclipse.sirius.components.representations.Success;
import org.eclipse.sirius.components.representations.VariableManager;

/**
* Provides the default description of the widget to use to support DataType feature of type java.time.Instant.
*
* @author lfasani
*/
public class InstantIfDescriptionProvider {
private static final String IF_DESCRIPTION_ID = "java.time.Instant";

private static final String DATE_TIME_DESCRIPTION_ID = "DateTime";

private final ComposedAdapterFactory composedAdapterFactory;

private final IPropertiesValidationProvider propertiesValidationProvider;

private final Function<VariableManager, String> semanticTargetIdProvider;

public InstantIfDescriptionProvider(ComposedAdapterFactory composedAdapterFactory, IPropertiesValidationProvider propertiesValidationProvider, Function<VariableManager, String> semanticTargetIdProvider) {
this.composedAdapterFactory = Objects.requireNonNull(composedAdapterFactory);
this.propertiesValidationProvider = Objects.requireNonNull(propertiesValidationProvider);
this.semanticTargetIdProvider = Objects.requireNonNull(semanticTargetIdProvider);
}

public IfDescription getIfDescription() {
return IfDescription.newIfDescription(IF_DESCRIPTION_ID)
.targetObjectIdProvider(this.semanticTargetIdProvider)
.predicate(this.getPredicate())
.controlDescriptions(List.of(this.getDateTimeDescription()))
.build();
}

private Function<VariableManager, Boolean> getPredicate() {
return variableManager -> {
var optionalEAttribute = variableManager.get(EMFFormDescriptionProvider.ESTRUCTURAL_FEATURE, EAttribute.class);
return optionalEAttribute.filter(eAttribute -> {
EClassifier eType = eAttribute.getEType();
return !eAttribute.isMany() && Objects.equals(eType.getInstanceClassName(), Instant.class.getName());
}).isPresent();
};
}

private DateTimeDescription getDateTimeDescription() {
return DateTimeDescription.newDateTimeDescription(DATE_TIME_DESCRIPTION_ID)
.idProvider(new WidgetIdProvider())
.targetObjectIdProvider(this.semanticTargetIdProvider)
.labelProvider(this.getLabelProvider())
.stringValueProvider(this.getValueProvider())
.newValueHandler(this.getNewValueHandler())
.diagnosticsProvider(this.propertiesValidationProvider.getDiagnosticsProvider())
.kindProvider(this.propertiesValidationProvider.getKindProvider())
.messageProvider(this.propertiesValidationProvider.getMessageProvider())
.type(DateTimeType.DATE_TIME)
.build();
}

private Function<VariableManager, String> getLabelProvider() {
return new EStructuralFeatureLabelProvider(EMFFormDescriptionProvider.ESTRUCTURAL_FEATURE, this.composedAdapterFactory);
}

private Function<VariableManager, String> getValueProvider() {
return variableManager -> {
var optionalEObject = variableManager.get(VariableManager.SELF, EObject.class);
var optionalEAttribute = variableManager.get(EMFFormDescriptionProvider.ESTRUCTURAL_FEATURE, EAttribute.class);

if (optionalEObject.isPresent() && optionalEAttribute.isPresent()) {
EObject eObject = optionalEObject.get();
EAttribute eAttribute = optionalEAttribute.get();

Object value = eObject.eGet(eAttribute);
if (value instanceof Instant instant) {
return DateTimeFormatter.ISO_INSTANT.format(instant);
}
}

return "";
};
}

private BiFunction<VariableManager, String, IStatus> getNewValueHandler() {
return (variableManager, newValue) -> {
IStatus status = new Failure("");
var optionalEObject = variableManager.get(VariableManager.SELF, EObject.class);
var optionalEAttribute = variableManager.get(EMFFormDescriptionProvider.ESTRUCTURAL_FEATURE, EAttribute.class);
if (optionalEObject.isPresent() && optionalEAttribute.isPresent()) {
EObject eObject = optionalEObject.get();
EAttribute eAttribute = optionalEAttribute.get();

if (newValue == null || newValue.isBlank()) {
eObject.eSet(eAttribute, null);
status = new Success();
} else {
Instant instant = Instant.parse(newValue);
eObject.eSet(eAttribute, instant);
status = new Success();
}
}
return status;
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*******************************************************************************
* Copyright (c) 2024 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.components.emf.forms;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;

import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.sirius.components.emf.forms.api.IPropertiesValidationProvider;
import org.eclipse.sirius.components.forms.DateTimeType;
import org.eclipse.sirius.components.forms.WidgetIdProvider;
import org.eclipse.sirius.components.forms.description.DateTimeDescription;
import org.eclipse.sirius.components.forms.description.IfDescription;
import org.eclipse.sirius.components.representations.Failure;
import org.eclipse.sirius.components.representations.IStatus;
import org.eclipse.sirius.components.representations.Success;
import org.eclipse.sirius.components.representations.VariableManager;

/**
* Provides the default description of the widget to use to support DataType feature of type java.time.LocalDate.
*
* @author lfasani
*/
public class LocalDateIfDescriptionProvider {
private static final String IF_DESCRIPTION_ID = "java.time.LocalDate";

private static final String DATE_DESCRIPTION_ID = "Date";

private final ComposedAdapterFactory composedAdapterFactory;

private final IPropertiesValidationProvider propertiesValidationProvider;

private final Function<VariableManager, String> semanticTargetIdProvider;

public LocalDateIfDescriptionProvider(ComposedAdapterFactory composedAdapterFactory, IPropertiesValidationProvider propertiesValidationProvider, Function<VariableManager, String> semanticTargetIdProvider) {
this.composedAdapterFactory = Objects.requireNonNull(composedAdapterFactory);
this.propertiesValidationProvider = Objects.requireNonNull(propertiesValidationProvider);
this.semanticTargetIdProvider = Objects.requireNonNull(semanticTargetIdProvider);
}

public IfDescription getIfDescription() {
return IfDescription.newIfDescription(IF_DESCRIPTION_ID)
.targetObjectIdProvider(this.semanticTargetIdProvider)
.predicate(this.getPredicate())
.controlDescriptions(List.of(this.getDateTimeDescription()))
.build();
}

private Function<VariableManager, Boolean> getPredicate() {
return variableManager -> {
var optionalEAttribute = variableManager.get(EMFFormDescriptionProvider.ESTRUCTURAL_FEATURE, EAttribute.class);
return optionalEAttribute.filter(eAttribute -> {
EClassifier eType = eAttribute.getEType();
return !eAttribute.isMany() && Objects.equals(eType.getInstanceClassName(), LocalDate.class.getName());
}).isPresent();
};
}

private DateTimeDescription getDateTimeDescription() {
return DateTimeDescription.newDateTimeDescription(DATE_DESCRIPTION_ID)
.idProvider(new WidgetIdProvider())
.targetObjectIdProvider(this.semanticTargetIdProvider)
.labelProvider(this.getLabelProvider())
.stringValueProvider(this.getValueProvider())
.newValueHandler(this.getNewValueHandler())
.diagnosticsProvider(this.propertiesValidationProvider.getDiagnosticsProvider())
.kindProvider(this.propertiesValidationProvider.getKindProvider())
.messageProvider(this.propertiesValidationProvider.getMessageProvider())
.type(DateTimeType.DATE)
.build();
}

private Function<VariableManager, String> getLabelProvider() {
return new EStructuralFeatureLabelProvider(EMFFormDescriptionProvider.ESTRUCTURAL_FEATURE, this.composedAdapterFactory);
}

private Function<VariableManager, String> getValueProvider() {
return variableManager -> {
var optionalEObject = variableManager.get(VariableManager.SELF, EObject.class);
var optionalEAttribute = variableManager.get(EMFFormDescriptionProvider.ESTRUCTURAL_FEATURE, EAttribute.class);

if (optionalEObject.isPresent() && optionalEAttribute.isPresent()) {
EObject eObject = optionalEObject.get();
EAttribute eAttribute = optionalEAttribute.get();

Object value = eObject.eGet(eAttribute);
if (value instanceof LocalDate localDate) {
Instant instant = localDate.atStartOfDay(ZoneId.of("UTC")).toInstant();
return DateTimeFormatter.ISO_INSTANT.format(instant);
}
}
return "";
};
}

private BiFunction<VariableManager, String, IStatus> getNewValueHandler() {
return (variableManager, newValue) -> {
IStatus status = new Failure("");
var optionalEObject = variableManager.get(VariableManager.SELF, EObject.class);
var optionalEAttribute = variableManager.get(EMFFormDescriptionProvider.ESTRUCTURAL_FEATURE, EAttribute.class);
if (optionalEObject.isPresent() && optionalEAttribute.isPresent()) {
EObject eObject = optionalEObject.get();
EAttribute eAttribute = optionalEAttribute.get();

if (newValue == null || newValue.isBlank()) {
eObject.eSet(eAttribute, null);
status = new Success();
} else {
Instant instant = Instant.parse(newValue);
LocalDate localDate = LocalDateTime.ofInstant(instant, ZoneOffset.UTC).toLocalDate();
eObject.eSet(eAttribute, localDate);
status = new Success();
}
}
return status;
};
}
}
Loading

0 comments on commit debe92a

Please sign in to comment.