From e220f24ddfd98e51396320b9a646b43f986a7555 Mon Sep 17 00:00:00 2001 From: Nicolas Couvert Date: Fri, 26 Jun 2026 12:02:11 +0200 Subject: [PATCH] [54] Add an option to choose task time granularity The option is client-side only Issue: https://github.com/ObeoNetwork/pepper/issues/54 --- CHANGELOG.adoc | 2 + .../provider/AbstractTaskItemProvider.java | 18 ++ .../src/main/resources/plugin.properties | 6 + .../src/main/resources/plugin_fr.properties | 6 + .../java/pepper/peppermm/AbstractTask.java | 26 +++ .../pepper/peppermm/DurationViewMode.java | 215 ++++++++++++++++++ .../java/pepper/peppermm/PepperPackage.java | 101 +++++++- .../peppermm/impl/AbstractTaskImpl.java | 56 +++++ .../peppermm/impl/PepperFactoryImpl.java | 25 ++ .../peppermm/impl/PepperPackageImpl.java | 36 +++ .../src/main/resources/model/pepper.ecore | 5 + .../src/main/resources/model/pepper.genmodel | 5 + .../AbstractTaskPropertiesConfigurer.java | 117 +++++++++- .../WorkpackagePropertiesConfigurer.java | 2 +- 14 files changed, 604 insertions(+), 16 deletions(-) create mode 100644 backend/pepper-mm/src/main/java/pepper/peppermm/DurationViewMode.java diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index d8a83e9..620994a 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -10,6 +10,8 @@ - https://github.com/ObeoNetwork/pepper/issues/9[#9] Add DependencyLink to add real delay between dependencies - https://github.com/ObeoNetwork/pepper/issues/8[#8] Determine the end time based on the start time and a duration +- https://github.com/ObeoNetwork/pepper/issues/54[#54] Add an option to choose task time granularity + === Improvements diff --git a/backend/pepper-edit/src/main/java/pepper/peppermm/provider/AbstractTaskItemProvider.java b/backend/pepper-edit/src/main/java/pepper/peppermm/provider/AbstractTaskItemProvider.java index ab5f848..0a7c58e 100644 --- a/backend/pepper-edit/src/main/java/pepper/peppermm/provider/AbstractTaskItemProvider.java +++ b/backend/pepper-edit/src/main/java/pepper/peppermm/provider/AbstractTaskItemProvider.java @@ -79,6 +79,7 @@ public List getPropertyDescriptors(Object object) { addAssignedTeamsPropertyDescriptor(object); addCalculationOptionPropertyDescriptor(object); addDurationPropertyDescriptor(object); + addDurationViewModePropertyDescriptor(object); } return itemPropertyDescriptors; } @@ -206,6 +207,22 @@ protected void addDurationPropertyDescriptor(Object object) { PepperPackage.Literals.ABSTRACT_TASK__DURATION, true, false, false, ItemPropertyDescriptor.INTEGRAL_VALUE_IMAGE, null, null)); } + /** + * This adds a property descriptor for the Duration View Mode feature. + * + * @generated + */ + protected void addDurationViewModePropertyDescriptor(Object object) { + itemPropertyDescriptors + .add(createItemPropertyDescriptor(((ComposeableAdapterFactory) adapterFactory).getRootAdapterFactory(), + getResourceLocator(), getString("_UI_AbstractTask_durationViewMode_feature"), + getString("_UI_PropertyDescriptor_description", "_UI_AbstractTask_durationViewMode_feature", + "_UI_AbstractTask_type"), + PepperPackage.Literals.ABSTRACT_TASK__DURATION_VIEW_MODE, true, false, false, + ItemPropertyDescriptor.GENERIC_VALUE_IMAGE, null, null)); + } + /** * This specifies how to implement {@link #getChildren} and is used to deduce an appropriate feature for an * {@link org.eclipse.emf.edit.command.AddCommand}, {@link org.eclipse.emf.edit.command.RemoveCommand} or @@ -277,6 +294,7 @@ public void notifyChanged(Notification notification) { case PepperPackage.ABSTRACT_TASK__COMPUTE_START_END_DYNAMICALLY: case PepperPackage.ABSTRACT_TASK__CALCULATION_OPTION: case PepperPackage.ABSTRACT_TASK__DURATION: + case PepperPackage.ABSTRACT_TASK__DURATION_VIEW_MODE: fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), false, true)); return; case PepperPackage.ABSTRACT_TASK__SUB_TASKS: diff --git a/backend/pepper-edit/src/main/resources/plugin.properties b/backend/pepper-edit/src/main/resources/plugin.properties index 045c737..a1d23e5 100644 --- a/backend/pepper-edit/src/main/resources/plugin.properties +++ b/backend/pepper-edit/src/main/resources/plugin.properties @@ -71,6 +71,8 @@ _UI_AbstractTask_subTasks_feature = Sub Tasks _UI_AbstractTask_calculationOption_feature = Calculation Option _UI_AbstractTask_durationDelay_feature = Delay (H) _UI_AbstractTask_duration_feature = Duration (Hours) +_UI_AbstractTask_duration_Days_feature = Duration (Days) +_UI_AbstractTask_durationViewMode_feature = Duration View Mode _UI_TagFolder_name_feature = Name _UI_TagFolder_ownedTags_feature = Owned Tags _UI_TagFolder_subFolders_feature = Sub Folders @@ -154,6 +156,8 @@ _UI_TaskTimeBoundariesConstraint_EndDuration_feature = End - Duration _UI_TaskTimeBoundariesConstraint_StartDuration_feature = Start - Duration _UI_StartOrEnd_Start_feature = Start _UI_StartOrEnd_End_feature = End +_UI_DurationViewMode_Hours_feature = Hours +_UI_DurationViewMode_Days_feature = Days _UI_Unknown_feature = Unspecified _UI_ProjectState_OnGoing_literal = ON_GOING @@ -185,3 +189,5 @@ _UI_StartOrEnd_End_literal = END _UI_TaskTimeBoundariesConstraint_StartEnd_literal = START_END _UI_TaskTimeBoundariesConstraint_EndDuration_literal = END_DURATION _UI_TaskTimeBoundariesConstraint_StartDuration_literal = START_DURATION +_UI_DurationViewMode_Hours_literal = HOURS +_UI_DurationViewMode_Days_literal = DAYS diff --git a/backend/pepper-edit/src/main/resources/plugin_fr.properties b/backend/pepper-edit/src/main/resources/plugin_fr.properties index ac9994c..13a37b6 100644 --- a/backend/pepper-edit/src/main/resources/plugin_fr.properties +++ b/backend/pepper-edit/src/main/resources/plugin_fr.properties @@ -72,6 +72,8 @@ _UI_AbstractTask_subTasks_feature = Sous t\u00E2ches _UI_AbstractTask_calculationOption_feature = Option de calcul _UI_AbstractTask_durationDelay_feature = Délais (H) _UI_AbstractTask_duration_feature = Dur\u00E9e (Heures) +_UI_AbstractTask_duration_Days_feature = Durée (Jours) +_UI_AbstractTask_durationViewMode_feature = Mode de durée _UI_TagFolder_name_feature = Nom _UI_TagFolder_ownedTags_feature = Tags _UI_TagFolder_subFolders_feature = Sous r\u00E9pertoires @@ -155,6 +157,8 @@ _UI_TaskTimeBoundariesConstraint_EndDuration_feature = Fin - Dur _UI_TaskTimeBoundariesConstraint_StartDuration_feature = Début - Durée _UI_StartOrEnd_Start_feature = Début _UI_StartOrEnd_End_feature = Fin +_UI_DurationViewMode_Hours_feature = Heures +_UI_DurationViewMode_Days_feature = Jours _UI_Unknown_feature = Unspecified _UI_WorkpackageArtefactNature_Delivrable_literal = DELIVRABLE @@ -186,3 +190,5 @@ _UI_StartOrEnd_End_literal = END _UI_TaskTimeBoundariesConstraint_StartEnd_literal = START_END _UI_TaskTimeBoundariesConstraint_EndDuration_literal = END_DURATION _UI_TaskTimeBoundariesConstraint_StartDuration_literal = START_DURATION +_UI_DurationViewMode_Hours_literal = HOURS +_UI_DurationViewMode_Days_literal = DAYS diff --git a/backend/pepper-mm/src/main/java/pepper/peppermm/AbstractTask.java b/backend/pepper-mm/src/main/java/pepper/peppermm/AbstractTask.java index 9d17c7b..c36fd44 100644 --- a/backend/pepper-mm/src/main/java/pepper/peppermm/AbstractTask.java +++ b/backend/pepper-mm/src/main/java/pepper/peppermm/AbstractTask.java @@ -37,6 +37,7 @@ *
  • {@link AbstractTask#getSubTasks Sub Tasks}
  • *
  • {@link AbstractTask#getCalculationOption Calculation Option}
  • *
  • {@link AbstractTask#getDuration Duration}
  • + *
  • {@link AbstractTask#getDurationViewMode Duration View Mode}
  • * * * @see PepperPackage#getAbstractTask() @@ -269,4 +270,29 @@ public interface AbstractTask extends EObject { */ void setDuration(int value); + /** + * Returns the value of the 'Duration View Mode' attribute. The literals are from the enumeration + * {@link DurationViewMode}. + * + * @return the value of the 'Duration View Mode' attribute. + * @see DurationViewMode + * @see #setDurationViewMode(DurationViewMode) + * @see PepperPackage#getAbstractTask_DurationViewMode() + * @model + * @generated + */ + DurationViewMode getDurationViewMode(); + + /** + * Sets the value of the '{@link AbstractTask#getDurationViewMode Duration View Mode}' + * attribute. + * + * @param value + * the new value of the 'Duration View Mode' attribute. + * @see DurationViewMode + * @see #getDurationViewMode() + * @generated + */ + void setDurationViewMode(DurationViewMode value); + } // AbstractTask diff --git a/backend/pepper-mm/src/main/java/pepper/peppermm/DurationViewMode.java b/backend/pepper-mm/src/main/java/pepper/peppermm/DurationViewMode.java new file mode 100644 index 0000000..327eb5d --- /dev/null +++ b/backend/pepper-mm/src/main/java/pepper/peppermm/DurationViewMode.java @@ -0,0 +1,215 @@ +/** + * Copyright (c) 2024, 2026 CEA LIST and Others. + * 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 pepper.peppermm; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.eclipse.emf.common.util.Enumerator; + +/** + * A representation of the literals of the enumeration 'Duration View Mode', and + * utility methods for working with them. + * + * @see pepper.peppermm.PepperPackage#getDurationViewMode() + * @model + * @generated + */ +public enum DurationViewMode implements Enumerator { + /** + * The 'Hours' literal object. + * + * @see #HOURS_VALUE + * @generated + * @ordered + */ + HOURS(0, "Hours", "HOURS"), + + /** + * The 'Days' literal object. + * + * @see #DAYS_VALUE + * @generated + * @ordered + */ + DAYS(1, "Days", "DAYS"); + + /** + * The 'Hours' literal value. + * + * @see #HOURS + * @model name="Hours" literal="HOURS" + * @generated + * @ordered + */ + public static final int HOURS_VALUE = 0; + + /** + * The 'Days' literal value. + * + * @see #DAYS + * @model name="Days" literal="DAYS" + * @generated + * @ordered + */ + public static final int DAYS_VALUE = 1; + + /** + * An array of all the 'Duration View Mode' enumerators. + * + * @generated + */ + private static final DurationViewMode[] VALUES_ARRAY = new DurationViewMode[] { HOURS, DAYS, }; + + /** + * A public read-only list of all the 'Duration View Mode' enumerators. + * + * @generated + */ + public static final List VALUES = Collections.unmodifiableList(Arrays.asList(VALUES_ARRAY)); + + /** + * Returns the 'Duration View Mode' literal with the specified literal value. + * + * @param literal + * the literal. + * @return the matching enumerator or null. + * @generated + */ + public static DurationViewMode get(String literal) { + for (int i = 0; i < VALUES_ARRAY.length; ++i) { + DurationViewMode result = VALUES_ARRAY[i]; + if (result.toString().equals(literal)) { + return result; + } + } + return null; + } + + /** + * Returns the 'Duration View Mode' literal with the specified name. + * + * @param name + * the name. + * @return the matching enumerator or null. + * @generated + */ + public static DurationViewMode getByName(String name) { + for (int i = 0; i < VALUES_ARRAY.length; ++i) { + DurationViewMode result = VALUES_ARRAY[i]; + if (result.getName().equals(name)) { + return result; + } + } + return null; + } + + /** + * Returns the 'Duration View Mode' literal with the specified integer value. + * + * @param value + * the integer value. + * @return the matching enumerator or null. + * @generated + */ + public static DurationViewMode get(int value) { + switch (value) { + case HOURS_VALUE: + return HOURS; + case DAYS_VALUE: + return DAYS; + default: + return null; + } + } + + /** + * + * + * @generated + */ + private final int value; + + /** + * + * + * @generated + */ + private final String name; + + /** + * + * + * @generated + */ + private final String literal; + + /** + * Only this class can construct instances. + * + * @generated + */ + private DurationViewMode(int value, String name, String literal) { + this.value = value; + this.name = name; + this.literal = literal; + } + + /** + * + * + * @generated + */ + @Override + public int getValue() { + return value; + } + + /** + * + * + * @generated + */ + @Override + public String getName() { + return name; + } + + /** + * + * + * @generated + */ + @Override + public String getLiteral() { + return literal; + } + + /** + * Returns the literal value of the enumerator, which is its string representation. + * + * @generated + */ + @Override + public String toString() { + return literal; + } + +} // DurationViewMode diff --git a/backend/pepper-mm/src/main/java/pepper/peppermm/PepperPackage.java b/backend/pepper-mm/src/main/java/pepper/peppermm/PepperPackage.java index bd29ed2..816e225 100644 --- a/backend/pepper-mm/src/main/java/pepper/peppermm/PepperPackage.java +++ b/backend/pepper-mm/src/main/java/pepper/peppermm/PepperPackage.java @@ -435,6 +435,15 @@ public interface PepperPackage extends EPackage { */ int ABSTRACT_TASK__DURATION = 11; + /** + * The feature id for the 'Duration View Mode' attribute. + * + * @generated + * @ordered + */ + int ABSTRACT_TASK__DURATION_VIEW_MODE = 12; + /** * The number of structural features of the 'Abstract Task' class. @@ -442,7 +451,7 @@ public interface PepperPackage extends EPackage { * @generated * @ordered */ - int ABSTRACT_TASK_FEATURE_COUNT = 12; + int ABSTRACT_TASK_FEATURE_COUNT = 13; /** * The meta object id for the '{@link pepper.peppermm.impl.TagFolderImpl Tag Folder}' class. + * + * @generated + * @ordered + */ + int TASK__DURATION_VIEW_MODE = ABSTRACT_TASK__DURATION_VIEW_MODE; + /** * The feature id for the 'Dependencies' reference list. @@ -762,6 +780,15 @@ public interface PepperPackage extends EPackage { */ int OBJECTIVE__DURATION = ABSTRACT_TASK__DURATION; + /** + * The feature id for the 'Duration View Mode' attribute. + * + * @generated + * @ordered + */ + int OBJECTIVE__DURATION_VIEW_MODE = ABSTRACT_TASK__DURATION_VIEW_MODE; + /** * The feature id for the 'Owned Key Results' containment reference list. * @@ -891,6 +918,15 @@ public interface PepperPackage extends EPackage { */ int KEY_RESULT__DURATION = ABSTRACT_TASK__DURATION; + /** + * The feature id for the 'Duration View Mode' attribute. + * + * @generated + * @ordered + */ + int KEY_RESULT__DURATION_VIEW_MODE = ABSTRACT_TASK__DURATION_VIEW_MODE; + /** * The number of structural features of the 'Key Result' class. @@ -1618,7 +1654,17 @@ public interface PepperPackage extends EPackage { int TASK_TIME_BOUNDARIES_CONSTRAINT = 24; /** - * The meta object id for the '{@link RiskKind Risk Kind}' enum. + * The meta object id for the '{@link pepper.peppermm.DurationViewMode Duration View Mode}' enum. + * + * @see pepper.peppermm.DurationViewMode + * @see pepper.peppermm.impl.PepperPackageImpl#getDurationViewMode() + * @generated + */ + int DURATION_VIEW_MODE = 25; + + /** + * The meta object id for the '{@link pepper.peppermm.RiskKind Risk Kind}' enum. * * * @see RiskKind @@ -1654,7 +1700,7 @@ public interface PepperPackage extends EPackage { * @see pepper.peppermm.impl.PepperPackageImpl#getInstant() * @generated */ - int INSTANT = 26; + int INSTANT = 27; /** * The meta object id for the 'Date' data type. @@ -1663,7 +1709,7 @@ public interface PepperPackage extends EPackage { * @see pepper.peppermm.impl.PepperPackageImpl#getDate() * @generated */ - int DATE = 25; + int DATE = 26; /** * Returns the meta object for class '{@link Organization Organization}'. + * + * @return the meta object for the attribute 'Duration View Mode'. + * @see pepper.peppermm.AbstractTask#getDurationViewMode() + * @see #getAbstractTask() + * @generated + */ + EAttribute getAbstractTask_DurationViewMode(); + + /** + * Returns the meta object for class '{@link pepper.peppermm.TagFolder Tag Folder}'. * * @return the meta object for class 'Tag Folder'. @@ -2967,7 +3024,17 @@ public interface PepperPackage extends EPackage { EEnum getTaskTimeBoundariesConstraint(); /** - * Returns the meta object for enum '{@link RiskKind Risk Kind}'. + * Returns the meta object for enum '{@link pepper.peppermm.DurationViewMode Duration View Mode}'. + * + * @return the meta object for enum 'Duration View Mode'. + * @see pepper.peppermm.DurationViewMode + * @generated + */ + EEnum getDurationViewMode(); + + /** + * Returns the meta object for enum '{@link pepper.peppermm.RiskKind Risk Kind}'. * * * @return the meta object for enum 'Risk Kind'. @@ -3311,6 +3378,14 @@ interface Literals { */ EAttribute ABSTRACT_TASK__DURATION = eINSTANCE.getAbstractTask_Duration(); + /** + * The meta object literal for the 'Duration View Mode' attribute feature. + * + * @generated + */ + EAttribute ABSTRACT_TASK__DURATION_VIEW_MODE = eINSTANCE.getAbstractTask_DurationViewMode(); + /** * The meta object literal for the '{@link pepper.peppermm.impl.TagFolderImpl Tag Folder}' class. @@ -4044,8 +4119,18 @@ interface Literals { EEnum TASK_TIME_BOUNDARIES_CONSTRAINT = eINSTANCE.getTaskTimeBoundariesConstraint(); /** - * The meta object literal for the '{@link RiskKind Risk Kind}' enum. + * The meta object literal for the '{@link pepper.peppermm.DurationViewMode Duration View Mode}' enum. + * + * + * @see pepper.peppermm.DurationViewMode + * @see pepper.peppermm.impl.PepperPackageImpl#getDurationViewMode() + * @generated + */ + EEnum DURATION_VIEW_MODE = eINSTANCE.getDurationViewMode(); + + /** + * The meta object literal for the '{@link RiskKind Risk Kind}' enum. * * @see RiskKind * @see pepper.peppermm.impl.PepperPackageImpl#getRiskKind() diff --git a/backend/pepper-mm/src/main/java/pepper/peppermm/impl/AbstractTaskImpl.java b/backend/pepper-mm/src/main/java/pepper/peppermm/impl/AbstractTaskImpl.java index f4d91dd..5adcc4d 100644 --- a/backend/pepper-mm/src/main/java/pepper/peppermm/impl/AbstractTaskImpl.java +++ b/backend/pepper-mm/src/main/java/pepper/peppermm/impl/AbstractTaskImpl.java @@ -33,6 +33,7 @@ import org.eclipse.emf.ecore.util.InternalEList; import pepper.peppermm.AbstractTask; +import pepper.peppermm.DurationViewMode; import pepper.peppermm.PepperPackage; import pepper.peppermm.Person; import pepper.peppermm.Task; @@ -264,6 +265,26 @@ public abstract class AbstractTaskImpl extends MinimalEObjectImpl.Container impl */ protected int duration = DURATION_EDEFAULT; + /** + * The default value of the '{@link #getDurationViewMode() Duration View Mode}' attribute. + * + * @see #getDurationViewMode() + * @generated + * @ordered + */ + protected static final DurationViewMode DURATION_VIEW_MODE_EDEFAULT = DurationViewMode.HOURS; + + /** + * The cached value of the '{@link #getDurationViewMode() Duration View Mode}' attribute. + * + * @see #getDurationViewMode() + * @generated + * @ordered + */ + protected DurationViewMode durationViewMode = DURATION_VIEW_MODE_EDEFAULT; + /** * * @@ -570,6 +591,29 @@ public void setDuration(int newDuration) { } } + /** + * + * + * @generated + */ + @Override + public DurationViewMode getDurationViewMode() { + return durationViewMode; + } + + /** + * + * + * @generated + */ + @Override + public void setDurationViewMode(DurationViewMode newDurationViewMode) { + DurationViewMode oldDurationViewMode = durationViewMode; + durationViewMode = newDurationViewMode == null ? DURATION_VIEW_MODE_EDEFAULT : newDurationViewMode; + if (eNotificationRequired()) + eNotify(new ENotificationImpl(this, Notification.SET, PepperPackage.ABSTRACT_TASK__DURATION_VIEW_MODE, oldDurationViewMode, durationViewMode)); + } + /** * * @@ -617,6 +661,8 @@ public Object eGet(int featureID, boolean resolve, boolean coreType) { return getCalculationOption(); case PepperPackage.ABSTRACT_TASK__DURATION: return getDuration(); + case PepperPackage.ABSTRACT_TASK__DURATION_VIEW_MODE: + return getDurationViewMode(); default: return super.eGet(featureID, resolve, coreType); } @@ -671,6 +717,9 @@ public void eSet(int featureID, Object newValue) { case PepperPackage.ABSTRACT_TASK__DURATION: setDuration((Integer) newValue); return; + case PepperPackage.ABSTRACT_TASK__DURATION_VIEW_MODE: + setDurationViewMode((DurationViewMode) newValue); + return; default: super.eSet(featureID, newValue); return; @@ -721,6 +770,9 @@ public void eUnset(int featureID) { case PepperPackage.ABSTRACT_TASK__DURATION: setDuration(DURATION_EDEFAULT); return; + case PepperPackage.ABSTRACT_TASK__DURATION_VIEW_MODE: + setDurationViewMode(DURATION_VIEW_MODE_EDEFAULT); + return; default: super.eUnset(featureID); return; @@ -759,6 +811,8 @@ public boolean eIsSet(int featureID) { return calculationOption != CALCULATION_OPTION_EDEFAULT; case PepperPackage.ABSTRACT_TASK__DURATION: return duration != DURATION_EDEFAULT; + case PepperPackage.ABSTRACT_TASK__DURATION_VIEW_MODE: + return durationViewMode != DURATION_VIEW_MODE_EDEFAULT; default: return super.eIsSet(featureID); } @@ -791,6 +845,8 @@ public String toString() { result.append(calculationOption); result.append(", duration: "); result.append(duration); + result.append(", durationViewMode: "); + result.append(durationViewMode); result.append(')'); return result.toString(); } diff --git a/backend/pepper-mm/src/main/java/pepper/peppermm/impl/PepperFactoryImpl.java b/backend/pepper-mm/src/main/java/pepper/peppermm/impl/PepperFactoryImpl.java index 3192a22..a5b575c 100644 --- a/backend/pepper-mm/src/main/java/pepper/peppermm/impl/PepperFactoryImpl.java +++ b/backend/pepper-mm/src/main/java/pepper/peppermm/impl/PepperFactoryImpl.java @@ -124,6 +124,8 @@ public Object createFromString(EDataType eDataType, String initialValue) { return createStartOrEndFromString(eDataType, initialValue); case PepperPackage.TASK_TIME_BOUNDARIES_CONSTRAINT: return createTaskTimeBoundariesConstraintFromString(eDataType, initialValue); + case PepperPackage.DURATION_VIEW_MODE: + return createDurationViewModeFromString(eDataType, initialValue); case PepperPackage.DATE: return createDateFromString(eDataType, initialValue); case PepperPackage.INSTANT: @@ -153,6 +155,8 @@ public String convertToString(EDataType eDataType, Object instanceValue) { return convertStartOrEndToString(eDataType, instanceValue); case PepperPackage.TASK_TIME_BOUNDARIES_CONSTRAINT: return convertTaskTimeBoundariesConstraintToString(eDataType, instanceValue); + case PepperPackage.DURATION_VIEW_MODE: + return convertDurationViewModeToString(eDataType, instanceValue); case PepperPackage.DATE: return convertDateToString(eDataType, instanceValue); case PepperPackage.INSTANT: @@ -402,6 +406,27 @@ public String convertTaskTimeBoundariesConstraintToString(EDataType eDataType, O return instanceValue == null ? null : instanceValue.toString(); } + /** + * + * + * @generated + */ + public DurationViewMode createDurationViewModeFromString(EDataType eDataType, String initialValue) { + DurationViewMode result = DurationViewMode.get(initialValue); + if (result == null) + throw new IllegalArgumentException("The value '" + initialValue + "' is not a valid enumerator of '" + eDataType.getName() + "'"); + return result; + } + + /** + * + * + * @generated + */ + public String convertDurationViewModeToString(EDataType eDataType, Object instanceValue) { + return instanceValue == null ? null : instanceValue.toString(); + } + /** * * diff --git a/backend/pepper-mm/src/main/java/pepper/peppermm/impl/PepperPackageImpl.java b/backend/pepper-mm/src/main/java/pepper/peppermm/impl/PepperPackageImpl.java index dcfe52c..18aa879 100644 --- a/backend/pepper-mm/src/main/java/pepper/peppermm/impl/PepperPackageImpl.java +++ b/backend/pepper-mm/src/main/java/pepper/peppermm/impl/PepperPackageImpl.java @@ -27,6 +27,7 @@ import pepper.peppermm.AbstractTask; import pepper.peppermm.DependencyLink; import pepper.peppermm.DependencyRelatedObject; +import pepper.peppermm.DurationViewMode; import pepper.peppermm.ExternalStakeholder; import pepper.peppermm.InternalStakeholder; import pepper.peppermm.KeyResult; @@ -212,6 +213,13 @@ public class PepperPackageImpl extends EPackageImpl implements PepperPackage { */ private EEnum taskTimeBoundariesConstraintEEnum = null; + /** + * + * + * @generated + */ + private EEnum durationViewModeEEnum = null; + /** * * @@ -628,6 +636,16 @@ public EAttribute getAbstractTask_Duration() { return (EAttribute) abstractTaskEClass.getEStructuralFeatures().get(11); } + /** + * + * + * @generated + */ + @Override + public EAttribute getAbstractTask_DurationViewMode() { + return (EAttribute) abstractTaskEClass.getEStructuralFeatures().get(12); + } + /** * * @@ -1508,6 +1526,16 @@ public EEnum getTaskTimeBoundariesConstraint() { return taskTimeBoundariesConstraintEEnum; } + /** + * + * + * @generated + */ + @Override + public EEnum getDurationViewMode() { + return durationViewModeEEnum; + } + /** * * @@ -1626,6 +1654,7 @@ public void createPackageContents() { createEReference(abstractTaskEClass, ABSTRACT_TASK__SUB_TASKS); createEAttribute(abstractTaskEClass, ABSTRACT_TASK__CALCULATION_OPTION); createEAttribute(abstractTaskEClass, ABSTRACT_TASK__DURATION); + createEAttribute(abstractTaskEClass, ABSTRACT_TASK__DURATION_VIEW_MODE); tagFolderEClass = createEClass(TAG_FOLDER); createEAttribute(tagFolderEClass, TAG_FOLDER__NAME); @@ -1730,6 +1759,7 @@ public void createPackageContents() { workpackageArtefactNatureEEnum = createEEnum(WORKPACKAGE_ARTEFACT_NATURE); startOrEndEEnum = createEEnum(START_OR_END); taskTimeBoundariesConstraintEEnum = createEEnum(TASK_TIME_BOUNDARIES_CONSTRAINT); + durationViewModeEEnum = createEEnum(DURATION_VIEW_MODE); // Create data types dateEDataType = createEDataType(DATE); @@ -1838,6 +1868,8 @@ public void initializePackageContents() { IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); initEAttribute(getAbstractTask_Duration(), ecorePackage.getEInt(), "duration", null, 0, 1, AbstractTask.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); + initEAttribute(getAbstractTask_DurationViewMode(), this.getDurationViewMode(), "durationViewMode", null, 0, 1, AbstractTask.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, + !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); initEClass(tagFolderEClass, TagFolder.class, "TagFolder", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); initEAttribute(getTagFolder_Name(), ecorePackage.getEString(), "name", null, 0, 1, TagFolder.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, @@ -2049,6 +2081,10 @@ public void initializePackageContents() { addEEnumLiteral(taskTimeBoundariesConstraintEEnum, TaskTimeBoundariesConstraint.END_DURATION); addEEnumLiteral(taskTimeBoundariesConstraintEEnum, TaskTimeBoundariesConstraint.START_DURATION); + initEEnum(durationViewModeEEnum, DurationViewMode.class, "DurationViewMode"); + addEEnumLiteral(durationViewModeEEnum, DurationViewMode.HOURS); + addEEnumLiteral(durationViewModeEEnum, DurationViewMode.DAYS); + // Initialize data types initEDataType(dateEDataType, LocalDate.class, "Date", IS_SERIALIZABLE, !IS_GENERATED_INSTANCE_CLASS); initEDataType(instantEDataType, Instant.class, "Instant", IS_SERIALIZABLE, !IS_GENERATED_INSTANCE_CLASS); diff --git a/backend/pepper-mm/src/main/resources/model/pepper.ecore b/backend/pepper-mm/src/main/resources/model/pepper.ecore index ea8109d..986b5d2 100644 --- a/backend/pepper-mm/src/main/resources/model/pepper.ecore +++ b/backend/pepper-mm/src/main/resources/model/pepper.ecore @@ -50,6 +50,7 @@ + @@ -214,4 +215,8 @@ + + + + diff --git a/backend/pepper-mm/src/main/resources/model/pepper.genmodel b/backend/pepper-mm/src/main/resources/model/pepper.genmodel index cb21253..7e0b715 100644 --- a/backend/pepper-mm/src/main/resources/model/pepper.genmodel +++ b/backend/pepper-mm/src/main/resources/model/pepper.genmodel @@ -53,6 +53,10 @@ + + + + @@ -93,6 +97,7 @@ + diff --git a/backend/pepper-starter/src/main/java/pepper/starter/services/AbstractTaskPropertiesConfigurer.java b/backend/pepper-starter/src/main/java/pepper/starter/services/AbstractTaskPropertiesConfigurer.java index 6230ee4..7b0cc2d 100644 --- a/backend/pepper-starter/src/main/java/pepper/starter/services/AbstractTaskPropertiesConfigurer.java +++ b/backend/pepper-starter/src/main/java/pepper/starter/services/AbstractTaskPropertiesConfigurer.java @@ -62,6 +62,7 @@ import pepper.peppermm.AbstractTask; import pepper.peppermm.DependencyLink; import pepper.peppermm.DependencyRelatedObject; +import pepper.peppermm.DurationViewMode; import pepper.peppermm.PepperPackage; import pepper.peppermm.Person; import pepper.peppermm.Project; @@ -161,6 +162,9 @@ private List getGeneralControlDescription() { var endTime = this.getEndTimeWidget(); controls.add(endTime); + var viewDurationMode = this.getViewDurationModeWidget(); + controls.add(viewDurationMode); + var duration = this.getDurationWidget(); controls.add(duration); @@ -275,11 +279,93 @@ else if (taskTimeBoundariesConstraint.equals(TaskTimeBoundariesConstraint.END_DU .build(); } + private RadioDescription getViewDurationModeWidget() { + Function optionSelectedProvider = variableManager -> { + var optionalDurationViewMode = variableManager.get(SelectComponent.CANDIDATE_VARIABLE, DurationViewMode.class); + if (optionalDurationViewMode.isPresent()) { + DurationViewMode durationViewMode = optionalDurationViewMode.get(); + String optionLitteralId = Integer.valueOf(durationViewMode.getValue()).toString(); + var optionalValue = variableManager.get(VariableManager.SELF, AbstractTask.class) + .map(AbstractTask::getDurationViewMode) + .map(DurationViewMode::getValue) + .map(String::valueOf); + if (optionalValue.isPresent()) { + String value = optionalValue.get(); + return optionLitteralId.equals(value); + } + } + return false; + }; + + BiFunction newValueHandler = (variableManager, newValue) -> { + var taskOpt = variableManager.get(VariableManager.SELF, AbstractTask.class); + if (taskOpt.isPresent()) { + if (newValue == null || newValue.isBlank()) { + taskOpt.get().setDurationViewMode(DurationViewMode.HOURS); + } else { + int integer = Integer.parseInt(newValue); + DurationViewMode newMode = DurationViewMode.get(integer); + taskOpt.get().setDurationViewMode(newMode); + } + return new Success(); + } else { + return new Failure(""); + } + }; + + Function optionLabelProvider = variableManager -> { + var durationViewModeOpt = variableManager.get(SelectComponent.CANDIDATE_VARIABLE, DurationViewMode.class); + String label = ""; + if (durationViewModeOpt.isPresent()) { + DurationViewMode durationViewMode = durationViewModeOpt.get(); + if (durationViewMode.equals(DurationViewMode.DAYS)) { + label = abstractTaskAdapter.getString("_UI_DurationViewMode_Days_feature"); + } + else { + label = abstractTaskAdapter.getString("_UI_DurationViewMode_Hours_feature"); + } + } + return label; + }; + + String id = "abstractTask.durationViewMode"; + return RadioDescription.newRadioDescription(id) + .idProvider(variableManager -> id) + .targetObjectIdProvider(this.propertiesConfigurerService.getSemanticTargetIdProvider()) + .labelProvider(variableManager -> abstractTaskAdapter.getString("_UI_AbstractTask_durationViewMode_feature")) + .isReadOnlyProvider(variableManager -> false) + .optionSelectedProvider(optionSelectedProvider) + .optionsProvider(variableManager -> DurationViewMode.VALUES) + .optionIdProvider(variableManager -> variableManager.get(SelectComponent.CANDIDATE_VARIABLE, DurationViewMode.class) + .map(DurationViewMode::getValue) + .map(String::valueOf) + .orElse("")) + .optionLabelProvider(optionLabelProvider) + .newValueHandler(newValueHandler) + .diagnosticsProvider(this.propertiesConfigurerService.getDiagnosticsProvider(PepperPackage.Literals.ABSTRACT_TASK__DURATION_VIEW_MODE)) + .kindProvider(this.propertiesConfigurerService.getKindProvider()) + .messageProvider(this.propertiesConfigurerService.getMessageProvider()) + .build(); + } + private TextfieldDescription getDurationWidget() { - Function valueProvider = variableManager -> variableManager.get(VariableManager.SELF, AbstractTask.class) - .map(AbstractTask::getDuration) - .map(String::valueOf) - .orElse("0"); + Function valueProvider = variableManager -> { + var durationOpt = variableManager.get(VariableManager.SELF, AbstractTask.class) + .map(AbstractTask::getDuration); + var durationViewModeOpt = variableManager.get(VariableManager.SELF, AbstractTask.class) + .map(AbstractTask::getDurationViewMode); + String value = "0"; + if (durationOpt.isPresent() && durationViewModeOpt.isPresent()) { + int duration = durationOpt.get(); + DurationViewMode durationViewMode = durationViewModeOpt.get(); + if (durationViewMode.equals(DurationViewMode.DAYS)) { + value = String.valueOf((duration / 12) * 0.5); + } else { + value = String.valueOf(duration); + } + } + return value; + }; BiFunction newValueHandler = (variableManager, newValue) -> { var taskOpt = variableManager.get(VariableManager.SELF, AbstractTask.class); if (taskOpt.isPresent()) { @@ -287,10 +373,16 @@ private TextfieldDescription getDurationWidget() { taskOpt.get().setDuration(0); } else { try { - int integer = Integer.parseInt(newValue); + int integer; var task = taskOpt.get(); + DurationViewMode durationViewMode = taskOpt.get().getDurationViewMode(); + if (durationViewMode.equals(DurationViewMode.DAYS)) { + integer = (int) (Float.parseFloat(newValue) * 24); + } else { + integer = Integer.parseInt(newValue); + } task.setDuration(integer); - service.editTask(task, task.getName(), task.getDescription(), task.getStartTime(), task.getEndTime(), task.getProgress(), true); + service.followMoveDependency((DependencyRelatedObject) task); } catch (NumberFormatException e) { // Ignore } @@ -301,6 +393,17 @@ private TextfieldDescription getDurationWidget() { } }; + Function labelProvider = variableManager -> { + var durationViewModeOpt = variableManager.get(VariableManager.SELF, AbstractTask.class) + .map(AbstractTask::getDurationViewMode); + String label = abstractTaskAdapter.getString("_UI_AbstractTask_duration_feature"); + DurationViewMode durationViewMode = durationViewModeOpt.get(); + if (durationViewMode.equals(DurationViewMode.DAYS)) { + return abstractTaskAdapter.getString("_UI_AbstractTask_duration_Days_feature"); + } + return label; + }; + String id = "abstractTask.duration"; return TextfieldDescription.newTextfieldDescription(id) .isReadOnlyProvider(vm -> vm.get(VariableManager.SELF, AbstractTask.class) @@ -308,7 +411,7 @@ private TextfieldDescription getDurationWidget() { .orElse(true)) .idProvider(variableManager -> id) .targetObjectIdProvider(this.propertiesConfigurerService.getSemanticTargetIdProvider()) - .labelProvider(variableManager -> abstractTaskAdapter.getString("_UI_AbstractTask_duration_feature")) + .labelProvider(labelProvider) .valueProvider(valueProvider) .newValueHandler(newValueHandler) .diagnosticsProvider(this.propertiesConfigurerService.getDiagnosticsProvider(PepperPackage.Literals.ABSTRACT_TASK__DURATION)) diff --git a/backend/pepper-starter/src/main/java/pepper/starter/services/WorkpackagePropertiesConfigurer.java b/backend/pepper-starter/src/main/java/pepper/starter/services/WorkpackagePropertiesConfigurer.java index 5548028..0a8b16d 100644 --- a/backend/pepper-starter/src/main/java/pepper/starter/services/WorkpackagePropertiesConfigurer.java +++ b/backend/pepper-starter/src/main/java/pepper/starter/services/WorkpackagePropertiesConfigurer.java @@ -276,7 +276,7 @@ private TextfieldDescription getDurationWidget() { int integer = Integer.parseInt(newValue); var workpackage = workpackageOpt.get(); workpackage.setDuration(integer); - service.editWorkpackage(workpackage, workpackage.getName(), workpackage.getDescription(), workpackage.getStartDate(), workpackage.getEndDate(), workpackage.getProgress(), true); + service.followMoveDependency(workpackage); } catch (NumberFormatException e) { // Ignore }