diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index a3096a1bf2..5217cbf608 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -107,6 +107,7 @@ The expression can return a string (with a prefix of the form `INFO:`, `WARNING: It can be used to add new elements before/after the default UI or to completely replace the UI with another one if needed. Because this new extension point offers complete control of this part of the UI, the `editProjectNavbarSubtitleExtensionPoint` has been removed. See `PapayaExtensionRegistry.tsx` for how the same result as before can be achieved with the new extension point. +- https://github.com/eclipse-sirius/sirius-web/issues/4403[#4403] [table] Add support of actions in table rows context menu === Improvements diff --git a/packages/sirius-web/backend/sirius-web-papaya/src/main/java/org/eclipse/sirius/web/papaya/representations/table/DeleteRowContextMenuEntryExecutor.java b/packages/sirius-web/backend/sirius-web-papaya/src/main/java/org/eclipse/sirius/web/papaya/representations/table/DeleteRowContextMenuEntryExecutor.java new file mode 100644 index 0000000000..7a867016aa --- /dev/null +++ b/packages/sirius-web/backend/sirius-web-papaya/src/main/java/org/eclipse/sirius/web/papaya/representations/table/DeleteRowContextMenuEntryExecutor.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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.web.papaya.representations.table; + +import java.util.Map; +import java.util.Objects; + +import org.eclipse.sirius.components.collaborative.api.ChangeKind; +import org.eclipse.sirius.components.collaborative.tables.api.IRowContextMenuEntryExecutor; +import org.eclipse.sirius.components.core.api.IEditService; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IObjectService; +import org.eclipse.sirius.components.representations.IStatus; +import org.eclipse.sirius.components.representations.Success; +import org.eclipse.sirius.components.tables.Line; +import org.eclipse.sirius.components.tables.Table; +import org.eclipse.sirius.components.tables.descriptions.TableDescription; +import org.springframework.stereotype.Service; + +/** + * This class is the implementation of {@link IRowContextMenuEntryExecutor} for the example Delete row action. + * + * @author Jerome Gout + */ +@Service +public class DeleteRowContextMenuEntryExecutor implements IRowContextMenuEntryExecutor { + + private final IEditService editService; + + private final IObjectService objectService; + + public DeleteRowContextMenuEntryExecutor(IEditService editService, IObjectService objectService) { + this.editService = Objects.requireNonNull(editService); + this.objectService = Objects.requireNonNull(objectService); + } + + @Override + public boolean canExecute(IEditingContext editingContext, TableDescription tableDescription, Table table, Line row, String rowMenuContextEntryId) { + return PackageTableRowContextMenuProvider.DELETE_ID.equals(rowMenuContextEntryId); + } + + @Override + public IStatus execute(IEditingContext editingContext, TableDescription tableDescription, Table table, Line row, String rowMenuContextEntryId) { + this.objectService.getObject(editingContext, row.getTargetObjectId()).ifPresent(this.editService::delete); + return new Success(ChangeKind.SEMANTIC_CHANGE, Map.of()); + } +} diff --git a/packages/sirius-web/backend/sirius-web-papaya/src/main/java/org/eclipse/sirius/web/papaya/representations/table/PackageTableRowContextMenuProvider.java b/packages/sirius-web/backend/sirius-web-papaya/src/main/java/org/eclipse/sirius/web/papaya/representations/table/PackageTableRowContextMenuProvider.java new file mode 100644 index 0000000000..38b3f3d4ca --- /dev/null +++ b/packages/sirius-web/backend/sirius-web-papaya/src/main/java/org/eclipse/sirius/web/papaya/representations/table/PackageTableRowContextMenuProvider.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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.web.papaya.representations.table; + +import java.util.List; +import java.util.Objects; + +import org.eclipse.sirius.components.collaborative.tables.api.IRowContextMenuEntryProvider; +import org.eclipse.sirius.components.collaborative.tables.dto.RowContextMenuEntry; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.tables.Line; +import org.eclipse.sirius.components.tables.Table; +import org.eclipse.sirius.components.tables.descriptions.TableDescription; +import org.springframework.stereotype.Service; + +/** + * Example of row context menu entries used inside the papaya package table. + * + * @author Jerome Gout + */ +@Service +public class PackageTableRowContextMenuProvider implements IRowContextMenuEntryProvider { + + public static final String DELETE_ID = "papaya-package-table-delete-row"; + + public static final String DELETE_LABEL = "Delete row"; + + @Override + public boolean canHandle(IEditingContext editingContext, TableDescription tableDescription, Table table, Line row) { + return Objects.equals(tableDescription.getId(), PackageTableRepresentationDescriptionProvider.TABLE_DESCRIPTION_ID); + } + + @Override + public List getRowContextMenuEntries(IEditingContext editingContext, TableDescription tableDescription, Table table, Line row) { + return List.of(new RowContextMenuEntry(DELETE_ID, DELETE_LABEL, List.of("/icons/full/obj16/row-delete.svg"))); + } +} diff --git a/packages/sirius-web/backend/sirius-web-papaya/src/main/resources/icons/full/obj16/row-delete.svg b/packages/sirius-web/backend/sirius-web-papaya/src/main/resources/icons/full/obj16/row-delete.svg new file mode 100644 index 0000000000..c3d65d14ca --- /dev/null +++ b/packages/sirius-web/backend/sirius-web-papaya/src/main/resources/icons/full/obj16/row-delete.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/controllers/tables/PapayaTableRowControllerIntegrationTests.java b/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/controllers/tables/PapayaTableRowControllerIntegrationTests.java index 697dd693bc..a74c685971 100644 --- a/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/controllers/tables/PapayaTableRowControllerIntegrationTests.java +++ b/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/controllers/tables/PapayaTableRowControllerIntegrationTests.java @@ -18,6 +18,8 @@ import com.jayway.jsonpath.JsonPath; import java.time.Duration; +import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; @@ -26,15 +28,19 @@ import org.eclipse.sirius.components.collaborative.dto.CreateRepresentationInput; import org.eclipse.sirius.components.collaborative.tables.TableEventInput; import org.eclipse.sirius.components.collaborative.tables.TableRefreshedEventPayload; +import org.eclipse.sirius.components.collaborative.tables.dto.InvokeRowContextMenuEntryInput; import org.eclipse.sirius.components.collaborative.tables.dto.ResetTableRowsHeightInput; import org.eclipse.sirius.components.collaborative.tables.dto.ResizeTableRowInput; import org.eclipse.sirius.components.core.api.SuccessPayload; import org.eclipse.sirius.components.tables.Line; +import org.eclipse.sirius.components.tables.tests.graphql.InvokeRowContextMenuEntryMutationRunner; import org.eclipse.sirius.components.tables.tests.graphql.ResetTableRowsHeightMutationRunner; import org.eclipse.sirius.components.tables.tests.graphql.ResizeTableRowMutationRunner; +import org.eclipse.sirius.components.tables.tests.graphql.RowContextMenuQueryRunner; import org.eclipse.sirius.components.tables.tests.graphql.TableEventSubscriptionRunner; import org.eclipse.sirius.web.AbstractIntegrationTests; import org.eclipse.sirius.web.data.PapayaIdentifiers; +import org.eclipse.sirius.web.papaya.representations.table.PackageTableRowContextMenuProvider; import org.eclipse.sirius.web.tests.data.GivenSiriusWebServer; import org.eclipse.sirius.web.tests.services.api.IGivenCommittedTransaction; import org.eclipse.sirius.web.tests.services.api.IGivenCreatedTableSubscription; @@ -58,7 +64,7 @@ */ @Transactional @SuppressWarnings("checkstyle:MultipleStringLiterals") -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = {"sirius.web.test.enabled=studio"}) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { "sirius.web.test.enabled=studio" }) public class PapayaTableRowControllerIntegrationTests extends AbstractIntegrationTests { private static final String MISSING_TABLE = "Missing table"; @@ -75,6 +81,12 @@ public class PapayaTableRowControllerIntegrationTests extends AbstractIntegratio @Autowired private ResetTableRowsHeightMutationRunner resetTableRowsHeightMutationRunner; + @Autowired + private InvokeRowContextMenuEntryMutationRunner invokeRowContextMenuEntryMutationRunner; + + @Autowired + private RowContextMenuQueryRunner rowContextMenuQueryRunner; + @Autowired private TableEventSubscriptionRunner tableEventSubscriptionRunner; @@ -208,4 +220,121 @@ public void givenTableWithAResizedRowWhenRowAResetRowsHeightMutationIsTriggeredT .thenCancel() .verify(Duration.ofSeconds(10)); } + + @Test + @GivenSiriusWebServer + @DisplayName("Given a table, when row context menu entries are queried, then the correct entries are returned") + public void giveATableWhenRowContextMenuEntriesAreQueriedThenTheCorrectEntriesAreReturned() { + this.givenCommittedTransaction.commit(); + + var tableEventInput = new TableEventInput(UUID.randomUUID(), PapayaIdentifiers.PAPAYA_PROJECT.toString(), PapayaIdentifiers.PAPAYA_PACKAGE_TABLE_REPRESENTATION.toString()); + var flux = this.tableEventSubscriptionRunner.run(tableEventInput); + + TestTransaction.flagForCommit(); + TestTransaction.end(); + TestTransaction.start(); + + var tableId = new AtomicReference(); + var rowId = new AtomicReference(); + + Consumer initialTableContentConsumer = payload -> Optional.of(payload) + .filter(DataFetcherResult.class::isInstance) + .map(DataFetcherResult.class::cast) + .map(DataFetcherResult::getData) + .filter(TableRefreshedEventPayload.class::isInstance) + .map(TableRefreshedEventPayload.class::cast) + .map(TableRefreshedEventPayload::table) + .ifPresentOrElse(table -> { + assertThat(table).isNotNull(); + assertThat(table.getLines()).hasSize(2); + tableId.set(table.getId()); + rowId.set(table.getLines().get(0).getId()); + }, () -> fail(MISSING_TABLE)); + + Runnable getContextMenuActions = () -> { + Map variables = Map.of( + "editingContextId", PapayaIdentifiers.PAPAYA_PROJECT.toString(), + "representationId", tableId.get(), + "tableId", tableId.get(), + "rowId", rowId.get().toString() + ); + var result = this.rowContextMenuQueryRunner.run(variables); + + List actionLabels = JsonPath.read(result, "$.data.viewer.editingContext.representation.description.rowContextMenuEntries[*].label"); + assertThat(actionLabels).isNotEmpty().hasSize(1); + assertThat(actionLabels.get(0)).isEqualTo("Delete row"); + }; + + StepVerifier.create(flux) + .consumeNextWith(initialTableContentConsumer) + .then(getContextMenuActions) + .thenCancel() + .verify(Duration.ofSeconds(10)); + } + + + @Test + @GivenSiriusWebServer + @DisplayName("Given a table, when a row context menu entry is triggered, then the entry is correctly invoked ") + public void giveATableWhenARowContextMenuEntryIsTriggeredThenTheEntryIsCorrectlyInvoked() { + this.givenCommittedTransaction.commit(); + + var tableEventInput = new TableEventInput(UUID.randomUUID(), PapayaIdentifiers.PAPAYA_PROJECT.toString(), PapayaIdentifiers.PAPAYA_PACKAGE_TABLE_REPRESENTATION.toString()); + var flux = this.tableEventSubscriptionRunner.run(tableEventInput); + + TestTransaction.flagForCommit(); + TestTransaction.end(); + TestTransaction.start(); + + var tableId = new AtomicReference(); + var rowId = new AtomicReference(); + + Consumer initialTableContentConsumer = payload -> Optional.of(payload) + .filter(DataFetcherResult.class::isInstance) + .map(DataFetcherResult.class::cast) + .map(DataFetcherResult::getData) + .filter(TableRefreshedEventPayload.class::isInstance) + .map(TableRefreshedEventPayload.class::cast) + .map(TableRefreshedEventPayload::table) + .ifPresentOrElse(table -> { + assertThat(table).isNotNull(); + assertThat(table.getLines()).hasSize(2); + tableId.set(table.getId()); + rowId.set(table.getLines().get(0).getId()); + }, () -> fail(MISSING_TABLE)); + + Runnable invokeDeleteRowAction = () -> { + var invokeRowContextMenuEntryInput = new InvokeRowContextMenuEntryInput( + UUID.randomUUID(), + PapayaIdentifiers.PAPAYA_PROJECT.toString(), + tableId.get(), + tableId.get(), + rowId.get(), + PackageTableRowContextMenuProvider.DELETE_ID + ); + var result = this.invokeRowContextMenuEntryMutationRunner.run(invokeRowContextMenuEntryInput); + + String typename = JsonPath.read(result, "$.data.invokeRowContextMenuEntry.__typename"); + assertThat(typename).isEqualTo(SuccessPayload.class.getSimpleName()); + }; + + Consumer updatedTableContentConsumer = payload -> Optional.of(payload) + .filter(DataFetcherResult.class::isInstance) + .map(DataFetcherResult.class::cast) + .map(DataFetcherResult::getData) + .filter(TableRefreshedEventPayload.class::isInstance) + .map(TableRefreshedEventPayload.class::cast) + .map(TableRefreshedEventPayload::table) + .ifPresentOrElse(table -> { + assertThat(table).isNotNull(); + assertThat(table.getLines()).hasSize(1); + }, () -> fail(MISSING_TABLE)); + + StepVerifier.create(flux) + .consumeNextWith(initialTableContentConsumer) + .then(invokeDeleteRowAction) + .consumeNextWith(updatedTableContentConsumer) + .thenCancel() + .verify(Duration.ofSeconds(10)); + } } diff --git a/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/controllers/tables/PapayaViewTableControllerIntegrationTests.java b/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/controllers/tables/PapayaViewTableControllerIntegrationTests.java index b936e72bf8..5a94cec048 100644 --- a/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/controllers/tables/PapayaViewTableControllerIntegrationTests.java +++ b/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/controllers/tables/PapayaViewTableControllerIntegrationTests.java @@ -15,15 +15,25 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; +import com.jayway.jsonpath.JsonPath; + import java.time.Duration; +import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import org.eclipse.sirius.components.collaborative.dto.CreateRepresentationInput; import org.eclipse.sirius.components.collaborative.tables.TableRefreshedEventPayload; +import org.eclipse.sirius.components.collaborative.tables.dto.InvokeRowContextMenuEntryInput; +import org.eclipse.sirius.components.core.api.SuccessPayload; +import org.eclipse.sirius.components.tables.Table; import org.eclipse.sirius.components.tables.TextareaCell; import org.eclipse.sirius.components.tables.TextfieldCell; +import org.eclipse.sirius.components.tables.tests.graphql.InvokeRowContextMenuEntryMutationRunner; +import org.eclipse.sirius.components.tables.tests.graphql.RowContextMenuQueryRunner; import org.eclipse.sirius.web.AbstractIntegrationTests; import org.eclipse.sirius.web.data.PapayaIdentifiers; import org.eclipse.sirius.web.services.tables.ViewTableDescriptionProvider; @@ -59,6 +69,11 @@ public class PapayaViewTableControllerIntegrationTests extends AbstractIntegrati @Autowired private ViewTableDescriptionProvider viewTableDescriptionProvider; + @Autowired + private RowContextMenuQueryRunner rowContextMenuQueryRunner; + + @Autowired + private InvokeRowContextMenuEntryMutationRunner invokeRowContextMenuEntryMutationRunner; @BeforeEach public void beforeEach() { @@ -82,31 +97,97 @@ private Flux givenSubscriptionToViewTableRepresentation() { public void givenSimpleViewTableDescriptionWhenSubscriptionIsCreatedThenTableIsRender() { var flux = this.givenSubscriptionToViewTableRepresentation(); - Consumer tableContentConsumer = payload -> Optional.of(payload) - .filter(TableRefreshedEventPayload.class::isInstance) - .map(TableRefreshedEventPayload.class::cast) - .map(TableRefreshedEventPayload::table) - .ifPresentOrElse(table -> { - assertThat(table).isNotNull(); - assertThat(table.getColumns()).hasSize(2); - assertThat(table.getColumns().get(0).getHeaderLabel()).isEqualTo("Name"); - assertThat(table.getColumns().get(0).getHeaderIndexLabel()).isEqualTo("0"); - assertThat(table.getColumns().get(1).getHeaderLabel()).isEqualTo("Description"); - assertThat(table.getColumns().get(1).getHeaderIndexLabel()).isEqualTo("1"); - assertThat(table.getLines()).hasSize(2); - assertThat(table.getLines().get(0).getHeaderIndexLabel()).isEqualTo("0"); - assertThat(table.getLines().get(0).getCells().get(0)).isInstanceOf(TextfieldCell.class); - assertThat(table.getLines().get(0).getCells().get(1)).isInstanceOf(TextareaCell.class); - assertThat(((TextfieldCell) table.getLines().get(0).getCells().get(0)).getValue()).isEqualTo("Success"); - assertThat(table.getLines().get(1).getHeaderIndexLabel()).isEqualTo("1"); - assertThat(table.getLines().get(1).getCells().get(0)).isInstanceOf(TextfieldCell.class); - assertThat(((TextfieldCell) table.getLines().get(1).getCells().get(0)).getValue()).isEqualTo("Failure"); - }, () -> fail("Missing table")); + Consumer tableContentConsumer = this.getTableSubscriptionConsumer(table -> { + assertThat(table).isNotNull(); + assertThat(table.getColumns()).hasSize(2); + assertThat(table.getColumns().get(0).getHeaderLabel()).isEqualTo("Name"); + assertThat(table.getColumns().get(0).getHeaderIndexLabel()).isEqualTo("0"); + assertThat(table.getColumns().get(1).getHeaderLabel()).isEqualTo("Description"); + assertThat(table.getColumns().get(1).getHeaderIndexLabel()).isEqualTo("1"); + assertThat(table.getLines()).hasSize(2); + assertThat(table.getLines().get(0).getHeaderIndexLabel()).isEqualTo("0"); + assertThat(table.getLines().get(0).getCells().get(0)).isInstanceOf(TextfieldCell.class); + assertThat(table.getLines().get(0).getCells().get(1)).isInstanceOf(TextareaCell.class); + assertThat(((TextfieldCell) table.getLines().get(0).getCells().get(0)).getValue()).isEqualTo("Success"); + assertThat(table.getLines().get(1).getHeaderIndexLabel()).isEqualTo("1"); + assertThat(table.getLines().get(1).getCells().get(0)).isInstanceOf(TextfieldCell.class); + assertThat(((TextfieldCell) table.getLines().get(1).getCells().get(0)).getValue()).isEqualTo("Failure"); + }); + + StepVerifier.create(flux) + .consumeNextWith(tableContentConsumer) + .thenCancel() + .verify(Duration.ofSeconds(10)); + } + + @Test + @GivenSiriusWebServer + @DisplayName("Given a simple view table description, when a row context menu entry is retrieved and invoked, then the row context menu entry is correctly executed") + public void givenSimpleViewTableDescriptionWhenRowContextMenuEntryIsInvokedThenRowContextMenuEntryIsCorrectlyExecuted() { + var flux = this.givenSubscriptionToViewTableRepresentation(); + + var tableId = new AtomicReference(); + var rowId = new AtomicReference(); + var rowLabel = new AtomicReference(); + Consumer tableContentConsumer = this.getTableSubscriptionConsumer(table -> { + assertThat(table).isNotNull(); + assertThat(table.getLines()).hasSize(2); + tableId.set(table.getId()); + rowId.set(table.getLines().get(0).getId()); + rowLabel.set(table.getLines().get(0).getHeaderLabel()); + }); + + var actionId = new AtomicReference(); + Runnable getContextMenuEntriesTask = () -> { + Map variables = Map.of( + "editingContextId", PapayaIdentifiers.PAPAYA_PROJECT.toString(), + "representationId", tableId.get(), + "tableId", tableId.get(), + "rowId", rowId.get().toString()); + + var result = this.rowContextMenuQueryRunner.run(variables); + List actionLabels = JsonPath.read(result, "$.data.viewer.editingContext.representation.description.rowContextMenuEntries[*].label"); + assertThat(actionLabels).isNotEmpty().hasSize(1); + assertThat(actionLabels.get(0)).isEqualTo("Change name"); + + List actionIds = JsonPath.read(result, "$.data.viewer.editingContext.representation.description.rowContextMenuEntries[*].id"); + actionId.set(actionIds.get(0)); + }; + + Runnable invokeChangeNameAction = () -> { + var invokeRowContextMenuEntryInput = new InvokeRowContextMenuEntryInput( + UUID.randomUUID(), + PapayaIdentifiers.PAPAYA_PROJECT.toString(), + tableId.get(), + tableId.get(), + rowId.get(), + actionId.get() + ); + var result = this.invokeRowContextMenuEntryMutationRunner.run(invokeRowContextMenuEntryInput); + + String typename = JsonPath.read(result, "$.data.invokeRowContextMenuEntry.__typename"); + assertThat(typename).isEqualTo(SuccessPayload.class.getSimpleName()); + }; + + Consumer updatedTableContentConsumer = this.getTableSubscriptionConsumer(table -> { + assertThat(table).isNotNull(); + assertThat(table.getLines().get(0).getHeaderLabel()).isEqualTo(rowLabel + "Updated"); + }); StepVerifier.create(flux) .consumeNextWith(tableContentConsumer) + .then(getContextMenuEntriesTask) + .then(invokeChangeNameAction) + .consumeNextWith(updatedTableContentConsumer) .thenCancel() .verify(Duration.ofSeconds(10)); } + private Consumer getTableSubscriptionConsumer(Consumer tableConsumer) { + return payload -> Optional.of(payload) + .filter(TableRefreshedEventPayload.class::isInstance) + .map(TableRefreshedEventPayload.class::cast) + .map(TableRefreshedEventPayload::table) + .ifPresentOrElse(tableConsumer, () -> fail("Missing table")); + } } diff --git a/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/services/tables/ViewTableDescriptionProvider.java b/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/services/tables/ViewTableDescriptionProvider.java index a48d50ddc2..dee334ee53 100644 --- a/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/services/tables/ViewTableDescriptionProvider.java +++ b/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/services/tables/ViewTableDescriptionProvider.java @@ -24,6 +24,7 @@ import org.eclipse.sirius.components.view.View; import org.eclipse.sirius.components.view.builder.generated.table.TableBuilders; import org.eclipse.sirius.components.view.builder.generated.view.ViewBuilder; +import org.eclipse.sirius.components.view.builder.generated.view.ViewBuilders; import org.eclipse.sirius.components.view.emf.table.TableIdProvider; import org.eclipse.sirius.components.view.table.TableDescription; import org.eclipse.sirius.emfjson.resource.JsonResource; @@ -88,9 +89,23 @@ private TableDescription createTableDescription() { .headerIndexLabelExpression("aql:columnIndex") .build(); + var contextMenuEntry = new TableBuilders().newRowContextMenuEntry() + .name("change-name") + .labelExpression("Change name") + .preconditionExpression("aql:true") + .body( + new ViewBuilders().newSetValue() + .featureName("name") + .valueExpression("aql:self.name + 'Updated'") + .build() + ) + .build(); + var rowDescription = new TableBuilders().newRowDescription() .semanticCandidatesExpression("aql:self.types") .headerIndexLabelExpression("aql:rowIndex") + .headerLabelExpression("aql:self.name") + .contextMenuEntries(contextMenuEntry) .build(); var nameCellDescription = new TableBuilders().newCellDescription() diff --git a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/TableQueryService.java b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/TableQueryService.java index 1096c91a8f..53c3270756 100644 --- a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/TableQueryService.java +++ b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/TableQueryService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024 Obeo. + * Copyright (c) 2024, 2025 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 @@ -43,6 +43,13 @@ public Optional findLineByCellId(Table table, UUID cellId) { .findFirst(); } + @Override + public Optional findLineById(Table table, UUID rowId) { + return table.getLines().stream() + .filter(row -> Objects.equals(rowId, row.getId())) + .findFirst(); + } + @Override public Optional findColumnById(Table table, UUID columnId) { return table.getColumns().stream() diff --git a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/api/IRowContextMenuEntryExecutor.java b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/api/IRowContextMenuEntryExecutor.java new file mode 100644 index 0000000000..bd6d4937a8 --- /dev/null +++ b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/api/IRowContextMenuEntryExecutor.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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.collaborative.tables.api; + +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.representations.IStatus; +import org.eclipse.sirius.components.tables.Line; +import org.eclipse.sirius.components.tables.Table; +import org.eclipse.sirius.components.tables.descriptions.TableDescription; + +/** + * Interface allowing to perform row context menu entries. + * + * @author Jerome Gout + */ +public interface IRowContextMenuEntryExecutor { + boolean canExecute(IEditingContext editingContext, TableDescription tableDescription, Table table, Line row, String rowMenuContextEntryId); + + IStatus execute(IEditingContext editingContext, TableDescription tableDescription, Table table, Line row, String rowMenuContextEntryId); +} diff --git a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/api/IRowContextMenuEntryProvider.java b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/api/IRowContextMenuEntryProvider.java new file mode 100644 index 0000000000..fb80fa873c --- /dev/null +++ b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/api/IRowContextMenuEntryProvider.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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.collaborative.tables.api; + +import java.util.List; + +import org.eclipse.sirius.components.collaborative.tables.dto.RowContextMenuEntry; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.tables.Line; +import org.eclipse.sirius.components.tables.Table; +import org.eclipse.sirius.components.tables.descriptions.TableDescription; + +/** + * Interface allowing to provide context menu entries in a table row. + * + * @author Jerome Gout + */ +public interface IRowContextMenuEntryProvider { + + boolean canHandle(IEditingContext editingContext, TableDescription tableDescription, Table table, Line row); + + List getRowContextMenuEntries(IEditingContext editingContext, TableDescription tableDescription, Table table, Line row); + +} diff --git a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/api/ITableQueryService.java b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/api/ITableQueryService.java index bb2eb84fba..322b4a8d1c 100644 --- a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/api/ITableQueryService.java +++ b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/api/ITableQueryService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024 Obeo. + * Copyright (c) 2024, 2025 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 @@ -29,7 +29,9 @@ public interface ITableQueryService { Optional findCellById(Table table, UUID cellId); - Optional findLineByCellId(Table table, UUID lineId); + Optional findLineByCellId(Table table, UUID cellId); + + Optional findLineById(Table table, UUID lineId); Optional findColumnById(Table table, UUID columnId); diff --git a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/dto/InvokeRowContextMenuEntryInput.java b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/dto/InvokeRowContextMenuEntryInput.java new file mode 100644 index 0000000000..6bc14667cf --- /dev/null +++ b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/dto/InvokeRowContextMenuEntryInput.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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.collaborative.tables.dto; + +import java.util.UUID; + +import org.eclipse.sirius.components.collaborative.tables.api.ITableInput; + +/** + * The input object for the row context menu entry invocation mutation. + * + * @author Jerome Gout + */ +public record InvokeRowContextMenuEntryInput( + UUID id, + String editingContextId, + String representationId, + String tableId, + UUID rowId, + String menuEntryId) implements ITableInput { +} \ No newline at end of file diff --git a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/dto/RowContextMenuEntriesInput.java b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/dto/RowContextMenuEntriesInput.java new file mode 100644 index 0000000000..7b531779b5 --- /dev/null +++ b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/dto/RowContextMenuEntriesInput.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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.collaborative.tables.dto; + +import java.util.UUID; + +import org.eclipse.sirius.components.collaborative.tables.api.ITableInput; + +/** + * The input of the table row context menu entries query. + * + * @author Jerome Gout + */ +public record RowContextMenuEntriesInput( + UUID id, + String editingContextId, + String representationId, + String tableId, + UUID rowId) implements ITableInput { +} \ No newline at end of file diff --git a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/dto/RowContextMenuEntry.java b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/dto/RowContextMenuEntry.java new file mode 100644 index 0000000000..fd804a126c --- /dev/null +++ b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/dto/RowContextMenuEntry.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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.collaborative.tables.dto; + +import java.util.List; +import java.util.Objects; + +/** + * Entry in the table row context menu. + * + * @author Jerome Gout + */ +public record RowContextMenuEntry(String id, String label, List iconURLs) { + public RowContextMenuEntry { + Objects.requireNonNull(id); + Objects.requireNonNull(label); + Objects.requireNonNull(iconURLs); + } +} diff --git a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/dto/RowContextMenuSuccessPayload.java b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/dto/RowContextMenuSuccessPayload.java new file mode 100644 index 0000000000..1d2d02ed9b --- /dev/null +++ b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/dto/RowContextMenuSuccessPayload.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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.collaborative.tables.dto; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +import org.eclipse.sirius.components.core.api.IPayload; + +/** + * Payload used to tell the frontend the list of context menu action. + * + * @author Jerome Gout + */ +public record RowContextMenuSuccessPayload(UUID id, List entries) implements IPayload { + public RowContextMenuSuccessPayload { + Objects.requireNonNull(id); + Objects.requireNonNull(entries); + } +} diff --git a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/handlers/InvokeRowContextMenuEntryEventHandler.java b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/handlers/InvokeRowContextMenuEntryEventHandler.java new file mode 100644 index 0000000000..9b6fc41807 --- /dev/null +++ b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/handlers/InvokeRowContextMenuEntryEventHandler.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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.collaborative.tables.handlers; + +import java.util.List; +import java.util.Objects; + +import org.eclipse.sirius.components.collaborative.api.ChangeDescription; +import org.eclipse.sirius.components.collaborative.api.ChangeKind; +import org.eclipse.sirius.components.collaborative.api.Monitoring; +import org.eclipse.sirius.components.collaborative.tables.api.IRowContextMenuEntryExecutor; +import org.eclipse.sirius.components.collaborative.tables.api.ITableContext; +import org.eclipse.sirius.components.collaborative.tables.api.ITableEventHandler; +import org.eclipse.sirius.components.collaborative.tables.api.ITableInput; +import org.eclipse.sirius.components.collaborative.tables.api.ITableQueryService; +import org.eclipse.sirius.components.collaborative.tables.dto.InvokeRowContextMenuEntryInput; +import org.eclipse.sirius.components.collaborative.tables.messages.ICollaborativeTableMessageService; +import org.eclipse.sirius.components.core.api.ErrorPayload; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IPayload; +import org.eclipse.sirius.components.core.api.SuccessPayload; +import org.eclipse.sirius.components.representations.Failure; +import org.eclipse.sirius.components.representations.Success; +import org.eclipse.sirius.components.tables.Line; +import org.eclipse.sirius.components.tables.descriptions.TableDescription; +import org.springframework.stereotype.Service; + +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.MeterRegistry; +import reactor.core.publisher.Sinks; + +/** + * Handle row context menu entry invocation event. + * + * @author Jerome Gout + */ +@Service +public class InvokeRowContextMenuEntryEventHandler implements ITableEventHandler { + + private final ICollaborativeTableMessageService messageService; + + private final ITableQueryService tableQueryService; + + private final Counter counter; + + private final List rowContextMenuEntryExecutors; + + public InvokeRowContextMenuEntryEventHandler(ICollaborativeTableMessageService messageService, ITableQueryService tableQueryService, MeterRegistry meterRegistry, List rowContextMenuEntryExecutors) { + this.messageService = messageService; + this.tableQueryService = Objects.requireNonNull(tableQueryService); + this.rowContextMenuEntryExecutors = Objects.requireNonNull(rowContextMenuEntryExecutors); + this.counter = Counter.builder(Monitoring.EVENT_HANDLER) + .tag(Monitoring.NAME, this.getClass().getSimpleName()) + .register(meterRegistry); + } + + @Override + public boolean canHandle(ITableInput tableInput) { + return tableInput instanceof InvokeRowContextMenuEntryInput; + } + + @Override + public void handle(Sinks.One payloadSink, Sinks.Many changeDescriptionSink, IEditingContext editingContext, ITableContext tableContext, TableDescription tableDescription, ITableInput tableInput) { + this.counter.increment(); + + ChangeDescription changeDescription = new ChangeDescription(ChangeKind.NOTHING, tableInput.representationId(), tableInput); + String message = this.messageService.invalidInput(tableInput.getClass().getSimpleName(), InvokeRowContextMenuEntryInput.class.getSimpleName()); + IPayload payload = new ErrorPayload(tableInput.id(), message); + + if (tableInput instanceof InvokeRowContextMenuEntryInput invokeRowContextMenuEntryInput) { + var optionalRow = this.tableQueryService.findLineById(tableContext.getTable(), invokeRowContextMenuEntryInput.rowId()); + if (optionalRow.isPresent()) { + Line row = optionalRow.get(); + var status = this.rowContextMenuEntryExecutors.stream() + .filter(executor -> executor.canExecute(editingContext, tableDescription, tableContext.getTable(), row, invokeRowContextMenuEntryInput.menuEntryId())) + .findFirst() + .map(executor -> executor.execute(editingContext, tableDescription, tableContext.getTable(), row, invokeRowContextMenuEntryInput.menuEntryId())) + .orElseGet(() -> new Failure(this.messageService.noRowContextMenuEntryExecutor())); + + if (status instanceof Success success) { + changeDescription = new ChangeDescription(success.getChangeKind(), tableInput.representationId(), tableInput, success.getParameters()); + payload = new SuccessPayload(tableInput.id()); + } else if (status instanceof Failure failure) { + payload = new ErrorPayload(tableInput.id(), failure.getMessages()); + } + } + } + + payloadSink.tryEmitValue(payload); + changeDescriptionSink.tryEmitNext(changeDescription); + } +} diff --git a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/handlers/ResetTableRowsHeightEventHandler.java b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/handlers/ResetTableRowsHeightEventHandler.java index 83462200da..be1408a225 100644 --- a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/handlers/ResetTableRowsHeightEventHandler.java +++ b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/handlers/ResetTableRowsHeightEventHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024 CEA LIST. + * Copyright (c) 2024, 2025 CEA LIST. * 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 @@ -19,7 +19,6 @@ import org.eclipse.sirius.components.collaborative.tables.api.ITableContext; import org.eclipse.sirius.components.collaborative.tables.api.ITableEventHandler; import org.eclipse.sirius.components.collaborative.tables.api.ITableInput; -import org.eclipse.sirius.components.collaborative.tables.dto.EditTextfieldCellInput; import org.eclipse.sirius.components.collaborative.tables.dto.ResetTableRowsHeightInput; import org.eclipse.sirius.components.collaborative.tables.messages.ICollaborativeTableMessageService; import org.eclipse.sirius.components.core.api.ErrorPayload; @@ -63,7 +62,7 @@ public void handle(Sinks.One payloadSink, Sinks.Many payloadSink, Sinks.Many contextMenuEntryProviders; + + public RowContextMenuEventHandler(ICollaborativeTableMessageService messageService, ITableQueryService tableQueryService, MeterRegistry meterRegistry, + List contextMenuEntryProviders) { + this.messageService = Objects.requireNonNull(messageService); + this.tableQueryService = Objects.requireNonNull(tableQueryService); + this.contextMenuEntryProviders = Objects.requireNonNull(contextMenuEntryProviders); + + this.counter = Counter.builder(Monitoring.EVENT_HANDLER) + .tag(Monitoring.NAME, this.getClass().getSimpleName()) + .register(meterRegistry); + } + + @Override + public boolean canHandle(ITableInput tableInput) { + return tableInput instanceof RowContextMenuEntriesInput; + } + + @Override + public void handle(Sinks.One payloadSink, Sinks.Many changeDescriptionSink, IEditingContext editingContext, ITableContext tableContext, + TableDescription tableDescription, ITableInput tableInput) { + this.counter.increment(); + + String message = this.messageService.invalidInput(tableInput.getClass().getSimpleName(), RowContextMenuEntriesInput.class.getSimpleName()); + IPayload payload = new ErrorPayload(tableInput.id(), message); + ChangeDescription changeDescription = new ChangeDescription(ChangeKind.NOTHING, tableInput.representationId(), tableInput); + + if (tableInput instanceof RowContextMenuEntriesInput input) { + var optionalRow = this.tableQueryService.findLineById(tableContext.getTable(), input.rowId()); + if (optionalRow.isPresent()) { + Line row = optionalRow.get(); + + var entries = this.contextMenuEntryProviders.stream() + .filter(provider -> provider.canHandle(editingContext, tableDescription, tableContext.getTable(), row)) + .flatMap(provider -> provider.getRowContextMenuEntries(editingContext, tableDescription, tableContext.getTable(), row).stream()) + .sorted(Comparator.comparing(RowContextMenuEntry::label)) + .toList(); + + payload = new RowContextMenuSuccessPayload(tableInput.id(), entries); + } + } + + changeDescriptionSink.tryEmitNext(changeDescription); + payloadSink.tryEmitValue(payload); + } +} diff --git a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/messages/CollaborativeTablesMessageService.java b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/messages/CollaborativeTablesMessageService.java index 0e5a1c30e2..832e12c780 100644 --- a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/messages/CollaborativeTablesMessageService.java +++ b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/messages/CollaborativeTablesMessageService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024 Obeo. + * Copyright (c) 2024, 2025 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 @@ -37,6 +37,11 @@ public String invalidInput(String expectedInputTypeName, String receivedInputTyp return this.messageSourceAccessor.getMessage(MessageConstants.INVALID_INPUT, new Object[] {expectedInputTypeName, receivedInputTypeName}); } + @Override + public String noRowContextMenuEntryExecutor() { + return this.messageSourceAccessor.getMessage(MessageConstants.NO_ROW_CONTEXT_MENU_ENTRY_FOUND); + } + @Override public String noHandlerFound() { return this.messageSourceAccessor.getMessage(MessageConstants.NO_HANDLER_FOUND); diff --git a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/messages/ICollaborativeTableMessageService.java b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/messages/ICollaborativeTableMessageService.java index 74940f6d62..1995bdb923 100644 --- a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/messages/ICollaborativeTableMessageService.java +++ b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/messages/ICollaborativeTableMessageService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024 Obeo. + * Copyright (c) 2024, 2025 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 @@ -21,6 +21,8 @@ public interface ICollaborativeTableMessageService { String invalidInput(String expectedInputTypeName, String receivedInputTypeName); + String noRowContextMenuEntryExecutor(); + String noHandlerFound(); /** @@ -35,6 +37,11 @@ public String invalidInput(String expectedInputTypeName, String receivedInputTyp return "invalidInput"; } + @Override + public String noRowContextMenuEntryExecutor() { + return "noRowContextMenuEntryFound"; + } + @Override public String noHandlerFound() { return "noHandlerFound"; diff --git a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/messages/MessageConstants.java b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/messages/MessageConstants.java index 20ce98cbd9..748008b32b 100644 --- a/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/messages/MessageConstants.java +++ b/packages/tables/backend/sirius-components-collaborative-tables/src/main/java/org/eclipse/sirius/components/collaborative/tables/messages/MessageConstants.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024 Obeo. + * Copyright (c) 2024, 2025 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 @@ -21,6 +21,7 @@ public final class MessageConstants { public static final String INVALID_INPUT = "INVALID_INPUT"; public static final String NO_HANDLER_FOUND = "NO_HANDLER_FOUND"; + public static final String NO_ROW_CONTEXT_MENU_ENTRY_FOUND = "NO_ROW_CONTEXT_MENU_ENTRY_FOUND"; private MessageConstants() { // Prevent instantiation diff --git a/packages/tables/backend/sirius-components-collaborative-tables/src/main/resources/messages/sirius-components-collaborative-tables.properties b/packages/tables/backend/sirius-components-collaborative-tables/src/main/resources/messages/sirius-components-collaborative-tables.properties index ac5dc3fb21..baadb2df60 100644 --- a/packages/tables/backend/sirius-components-collaborative-tables/src/main/resources/messages/sirius-components-collaborative-tables.properties +++ b/packages/tables/backend/sirius-components-collaborative-tables/src/main/resources/messages/sirius-components-collaborative-tables.properties @@ -1,5 +1,5 @@ ################################################################################################ -# Copyright (c) 2021 Obeo. All Rights Reserved. +# Copyright (c) 2021, 2025 Obeo. All Rights Reserved. # This software and the attached documentation are the exclusive ownership # of its authors and was conceded to the profit of Obeo SARL. # This software and the attached documentation are protected under the rights @@ -15,3 +15,4 @@ ################################################################################################ INVALID_INPUT=Invalid input type, "{0}" has been received while "{1}" was expected NO_HANDLER_FOUND=No handler found +NO_ROW_CONTEXT_MENU_ENTRY_FOUND=No existing action for this menu entry diff --git a/packages/tables/backend/sirius-components-collaborative-tables/src/main/resources/schema/table.graphqls b/packages/tables/backend/sirius-components-collaborative-tables/src/main/resources/schema/table.graphqls index b868249d1e..58dcfe9394 100644 --- a/packages/tables/backend/sirius-components-collaborative-tables/src/main/resources/schema/table.graphqls +++ b/packages/tables/backend/sirius-components-collaborative-tables/src/main/resources/schema/table.graphqls @@ -140,6 +140,13 @@ type IconLabelCell implements Cell { type TableDescription implements RepresentationDescription { id: ID! label: String! + rowContextMenuEntries(tableId: ID!, rowId: ID!): [RowContextMenuEntry!]! +} + +type RowContextMenuEntry { + id: ID! + label: String! + iconURLs: [String!]! } extend type Mutation { @@ -155,6 +162,7 @@ extend type Mutation { changeGlobalFilterValue(input: ChangeGlobalFilterValueInput!): ChangeGlobalFilterValuePayload! changeColumnFilter(input: ChangeColumnFilterInput!): ChangeColumnFilterPayload! reorderTableColumns(input: ReorderTableColumnsInput!): ReorderTableColumnsPayload! + invokeRowContextMenuEntry(input: InvokeRowContextMenuEntryInput!): InvokeRowContextMenuEntryPayload! } input EditCheckboxCellInput { @@ -292,3 +300,14 @@ input ReorderTableColumnsInput { } union ReorderTableColumnsPayload = ErrorPayload | SuccessPayload + +input InvokeRowContextMenuEntryInput { + id: ID! + editingContextId: ID! + representationId: ID! + tableId: ID! + rowId: ID! + menuEntryId: ID! +} + +union InvokeRowContextMenuEntryPayload = ErrorPayload | SuccessPayload diff --git a/packages/tables/backend/sirius-components-tables-graphql/src/main/java/org/eclipse/sirius/components/tables/graphql/datafetchers/RowContextMenuEntryIconURLsDataFetcher.java b/packages/tables/backend/sirius-components-tables-graphql/src/main/java/org/eclipse/sirius/components/tables/graphql/datafetchers/RowContextMenuEntryIconURLsDataFetcher.java new file mode 100644 index 0000000000..bc3ce8d383 --- /dev/null +++ b/packages/tables/backend/sirius-components-tables-graphql/src/main/java/org/eclipse/sirius/components/tables/graphql/datafetchers/RowContextMenuEntryIconURLsDataFetcher.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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.tables.graphql.datafetchers; + +import java.util.List; +import java.util.Objects; + +import org.eclipse.sirius.components.annotations.spring.graphql.QueryDataFetcher; +import org.eclipse.sirius.components.collaborative.tables.dto.RowContextMenuEntry; +import org.eclipse.sirius.components.core.api.IImageURLSanitizer; +import org.eclipse.sirius.components.graphql.api.IDataFetcherWithFieldCoordinates; +import org.eclipse.sirius.components.graphql.api.URLConstants; + +import graphql.schema.DataFetchingEnvironment; + +/** + * The data fetcher used to concatenate the server image URL to the icon of context menu entry of row. + * + * @author Jerome Gout + */ +@QueryDataFetcher(type = "RowContextMenuEntry", field = "iconURLs") +public class RowContextMenuEntryIconURLsDataFetcher implements IDataFetcherWithFieldCoordinates> { + + private final IImageURLSanitizer imageURLSanitizer; + + public RowContextMenuEntryIconURLsDataFetcher(IImageURLSanitizer imageURLSanitizer) { + this.imageURLSanitizer = Objects.requireNonNull(imageURLSanitizer); + } + + @Override + public List get(DataFetchingEnvironment environment) throws Exception { + RowContextMenuEntry source = environment.getSource(); + + return source.iconURLs().stream() + .map(url -> this.imageURLSanitizer.sanitize(URLConstants.IMAGE_BASE_PATH, url)) + .toList(); + } +} diff --git a/packages/tables/backend/sirius-components-tables-graphql/src/main/java/org/eclipse/sirius/components/tables/graphql/datafetchers/TableDescriptionRowContextMenuDataFetcher.java b/packages/tables/backend/sirius-components-tables-graphql/src/main/java/org/eclipse/sirius/components/tables/graphql/datafetchers/TableDescriptionRowContextMenuDataFetcher.java new file mode 100644 index 0000000000..7ffe60d360 --- /dev/null +++ b/packages/tables/backend/sirius-components-tables-graphql/src/main/java/org/eclipse/sirius/components/tables/graphql/datafetchers/TableDescriptionRowContextMenuDataFetcher.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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.tables.graphql.datafetchers; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +import org.eclipse.sirius.components.annotations.spring.graphql.QueryDataFetcher; +import org.eclipse.sirius.components.collaborative.api.IEditingContextEventProcessorRegistry; +import org.eclipse.sirius.components.collaborative.tables.dto.RowContextMenuEntriesInput; +import org.eclipse.sirius.components.collaborative.tables.dto.RowContextMenuEntry; +import org.eclipse.sirius.components.collaborative.tables.dto.RowContextMenuSuccessPayload; +import org.eclipse.sirius.components.graphql.api.IDataFetcherWithFieldCoordinates; +import org.eclipse.sirius.components.graphql.api.LocalContextConstants; + +import graphql.schema.DataFetchingEnvironment; + +/** + * Used to retrieve the table description context menu. + * + * @author Jerome Gout + */ +@QueryDataFetcher(type = "TableDescription", field = "rowContextMenuEntries") +public class TableDescriptionRowContextMenuDataFetcher implements IDataFetcherWithFieldCoordinates>> { + + private static final String TABLE_ID_ARGUMENT = "tableId"; + + private static final String ROW_ID_ARGUMENT = "rowId"; + + private final IEditingContextEventProcessorRegistry editingContextEventProcessorRegistry; + + public TableDescriptionRowContextMenuDataFetcher(IEditingContextEventProcessorRegistry editingContextEventProcessorRegistry) { + this.editingContextEventProcessorRegistry = Objects.requireNonNull(editingContextEventProcessorRegistry); + } + + @Override + public CompletableFuture> get(DataFetchingEnvironment environment) throws Exception { + Map localContext = environment.getLocalContext(); + String editingContextId = Optional.ofNullable(localContext.get(LocalContextConstants.EDITING_CONTEXT_ID)).map(Object::toString).orElse(null); + String representationId = Optional.ofNullable(localContext.get(LocalContextConstants.REPRESENTATION_ID)).map(Object::toString).orElse(null); + String tableId = environment.getArgument(TABLE_ID_ARGUMENT); + String rowId = environment.getArgument(ROW_ID_ARGUMENT); + + var input = new RowContextMenuEntriesInput(UUID.randomUUID(), editingContextId, representationId, tableId, UUID.fromString(rowId)); + return this.editingContextEventProcessorRegistry.dispatchEvent(editingContextId, input) + .filter(RowContextMenuSuccessPayload.class::isInstance) + .map(RowContextMenuSuccessPayload.class::cast) + .map(RowContextMenuSuccessPayload::entries) + .toFuture(); + } +} diff --git a/packages/tables/backend/sirius-components-tables-graphql/src/main/java/org/eclipse/sirius/components/tables/graphql/datafetchers/mutation/MutationInvokeRowContextMenuEntryDataFetcher.java b/packages/tables/backend/sirius-components-tables-graphql/src/main/java/org/eclipse/sirius/components/tables/graphql/datafetchers/mutation/MutationInvokeRowContextMenuEntryDataFetcher.java new file mode 100644 index 0000000000..a2bbab4a27 --- /dev/null +++ b/packages/tables/backend/sirius-components-tables-graphql/src/main/java/org/eclipse/sirius/components/tables/graphql/datafetchers/mutation/MutationInvokeRowContextMenuEntryDataFetcher.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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.tables.graphql.datafetchers.mutation; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.Objects; +import java.util.concurrent.CompletableFuture; + +import org.eclipse.sirius.components.annotations.spring.graphql.MutationDataFetcher; +import org.eclipse.sirius.components.collaborative.tables.dto.InvokeRowContextMenuEntryInput; +import org.eclipse.sirius.components.core.api.IPayload; +import org.eclipse.sirius.components.graphql.api.IDataFetcherWithFieldCoordinates; +import org.eclipse.sirius.components.graphql.api.IEditingContextDispatcher; +import org.eclipse.sirius.components.graphql.api.IExceptionWrapper; + +import graphql.schema.DataFetchingEnvironment; + +/** + * Data fetcher used to invoke an entry of the context menu of a table row. + * + * @author Jerome Gout + */ +@MutationDataFetcher(type = "Mutation", field = "invokeRowContextMenuEntry") +public class MutationInvokeRowContextMenuEntryDataFetcher implements IDataFetcherWithFieldCoordinates> { + + private static final String INPUT_ARGUMENT = "input"; + + private final ObjectMapper objectMapper; + + private final IExceptionWrapper exceptionWrapper; + + private final IEditingContextDispatcher editingContextDispatcher; + + public MutationInvokeRowContextMenuEntryDataFetcher(ObjectMapper objectMapper, IExceptionWrapper exceptionWrapper, IEditingContextDispatcher editingContextDispatcher) { + this.objectMapper = Objects.requireNonNull(objectMapper); + this.exceptionWrapper = Objects.requireNonNull(exceptionWrapper); + this.editingContextDispatcher = Objects.requireNonNull(editingContextDispatcher); + } + + @Override + public CompletableFuture get(DataFetchingEnvironment environment) throws Exception { + Object argument = environment.getArgument(INPUT_ARGUMENT); + var input = this.objectMapper.convertValue(argument, InvokeRowContextMenuEntryInput.class); + + return this.exceptionWrapper.wrapMono(() -> this.editingContextDispatcher.dispatchMutation(input.editingContextId(), input), input).toFuture(); + } + +} diff --git a/packages/tables/backend/sirius-components-tables-tests/src/main/java/org/eclipse/sirius/components/tables/tests/graphql/InvokeRowContextMenuEntryMutationRunner.java b/packages/tables/backend/sirius-components-tables-tests/src/main/java/org/eclipse/sirius/components/tables/tests/graphql/InvokeRowContextMenuEntryMutationRunner.java new file mode 100644 index 0000000000..4bd35783e6 --- /dev/null +++ b/packages/tables/backend/sirius-components-tables-tests/src/main/java/org/eclipse/sirius/components/tables/tests/graphql/InvokeRowContextMenuEntryMutationRunner.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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.tables.tests.graphql; + +import java.util.Objects; + +import org.eclipse.sirius.components.collaborative.tables.dto.InvokeRowContextMenuEntryInput; +import org.eclipse.sirius.components.graphql.tests.api.IGraphQLRequestor; +import org.eclipse.sirius.components.graphql.tests.api.IMutationRunner; +import org.springframework.stereotype.Service; + +/** + * Used to invoke a row context menu entry with the GraphQL API. + * + * @author Jerome Gout + */ +@Service +public class InvokeRowContextMenuEntryMutationRunner implements IMutationRunner { + + private static final String INVOKE_ROW_CONTEXT_MENU_ENTRY_MUTATION = """ + mutation invokeRowContextMenuEntry($input: InvokeRowContextMenuEntryInput!) { + invokeRowContextMenuEntry(input: $input) { + __typename + ... on ErrorPayload { + messages { + body + level + } + } + ... on SuccessPayload { + messages { + body + level + } + } + } + } + """; + + private final IGraphQLRequestor graphQLRequestor; + + public InvokeRowContextMenuEntryMutationRunner(IGraphQLRequestor graphQLRequestor) { + this.graphQLRequestor = Objects.requireNonNull(graphQLRequestor); + } + + @Override + public String run(InvokeRowContextMenuEntryInput input) { + return this.graphQLRequestor.execute(INVOKE_ROW_CONTEXT_MENU_ENTRY_MUTATION, input); + } +} diff --git a/packages/tables/backend/sirius-components-tables-tests/src/main/java/org/eclipse/sirius/components/tables/tests/graphql/RowContextMenuQueryRunner.java b/packages/tables/backend/sirius-components-tables-tests/src/main/java/org/eclipse/sirius/components/tables/tests/graphql/RowContextMenuQueryRunner.java new file mode 100644 index 0000000000..2d1761408e --- /dev/null +++ b/packages/tables/backend/sirius-components-tables-tests/src/main/java/org/eclipse/sirius/components/tables/tests/graphql/RowContextMenuQueryRunner.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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.tables.tests.graphql; + +import java.util.Map; +import java.util.Objects; + +import org.eclipse.sirius.components.graphql.tests.api.IGraphQLRequestor; +import org.eclipse.sirius.components.graphql.tests.api.IQueryRunner; +import org.springframework.stereotype.Service; + +/** + * Used to call a row context menu graphQL query for testing purpose. + * + * @author Jerome Gout + */ +@Service +public class RowContextMenuQueryRunner implements IQueryRunner { + + private static final String ROW_CONTEXT_MENU_QUERY = """ + query rowContextMenuQuery($editingContextId: ID!, $representationId: ID!, $tableId: ID!, $rowId: ID!) { + viewer { + editingContext(editingContextId: $editingContextId) { + representation(representationId: $representationId) { + description { + ... on TableDescription { + rowContextMenuEntries(tableId: $tableId, rowId: $rowId) { + __typename + id + label + iconURLs + } + } + } + } + } + } + } + """; + + private final IGraphQLRequestor graphQLRequestor; + + public RowContextMenuQueryRunner(IGraphQLRequestor graphQLRequestor) { + this.graphQLRequestor = Objects.requireNonNull(graphQLRequestor); + } + + @Override + public String run(Map variables) { + return this.graphQLRequestor.execute(ROW_CONTEXT_MENU_QUERY, variables); + + } +} diff --git a/packages/tables/backend/sirius-components-tables/src/main/java/org/eclipse/sirius/components/tables/descriptions/LineDescription.java b/packages/tables/backend/sirius-components-tables/src/main/java/org/eclipse/sirius/components/tables/descriptions/LineDescription.java index 2d983d52d5..98d43947c2 100644 --- a/packages/tables/backend/sirius-components-tables/src/main/java/org/eclipse/sirius/components/tables/descriptions/LineDescription.java +++ b/packages/tables/backend/sirius-components-tables/src/main/java/org/eclipse/sirius/components/tables/descriptions/LineDescription.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024 Obeo. + * Copyright (c) 2024, 2025 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 @@ -29,6 +29,11 @@ @Immutable public final class LineDescription { + /** + * The variable name used to store a reference to a row. + */ + public static final String SELECTED_ROW = "selectedRow"; + private String id; private Function targetObjectIdProvider; @@ -53,6 +58,10 @@ private LineDescription() { // Prevent instantiation } + public static Builder newLineDescription(String id) { + return new Builder(id); + } + public String getId() { return this.id; } @@ -93,10 +102,6 @@ public Predicate getIsResizablePredicate() { return this.isResizablePredicate; } - public static Builder newLineDescription(String id) { - return new Builder(id); - } - @Override public String toString() { String pattern = "{0} '{'id: {1}'}'"; diff --git a/packages/tables/backend/sirius-components-tables/src/main/java/org/eclipse/sirius/components/tables/descriptions/TableDescription.java b/packages/tables/backend/sirius-components-tables/src/main/java/org/eclipse/sirius/components/tables/descriptions/TableDescription.java index fa6dc3d251..14c59668e9 100644 --- a/packages/tables/backend/sirius-components-tables/src/main/java/org/eclipse/sirius/components/tables/descriptions/TableDescription.java +++ b/packages/tables/backend/sirius-components-tables/src/main/java/org/eclipse/sirius/components/tables/descriptions/TableDescription.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024 Obeo. + * Copyright (c) 2024, 2025 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 @@ -33,6 +33,11 @@ public final class TableDescription implements IRepresentationDescription { public static final String LABEL = "label"; + /** + * The variable name used to store a reference to a table. + */ + public static final String TABLE = "table"; + private String id; private String label; diff --git a/packages/tables/frontend/sirius-components-tables/src/representation/TableRepresentation.tsx b/packages/tables/frontend/sirius-components-tables/src/representation/TableRepresentation.tsx index cb78d6df7f..5a47b1ba5b 100644 --- a/packages/tables/frontend/sirius-components-tables/src/representation/TableRepresentation.tsx +++ b/packages/tables/frontend/sirius-components-tables/src/representation/TableRepresentation.tsx @@ -27,6 +27,9 @@ const useTableRepresentationStyles = makeStyles()((theme) => ({ justifyContent: 'center', paddingTop: theme.spacing(8), }, + representation: { + overflowX: 'auto', + }, })); export const TableRepresentation = ({ editingContextId, representationId, readOnly }: RepresentationComponentProps) => { @@ -73,7 +76,7 @@ export const TableRepresentation = ({ editingContextId, representationId, readOn } return ( -
+
{table !== null && !complete ? ( { + const [anchorEl, setAnchorEl] = useState(null); + + const handleOpenRowActionMenu = (event: MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + + return ( + <> + + + + + + {anchorEl != null ? ( + setAnchorEl(null)} + /> + ) : null} + + ); +}; diff --git a/packages/tables/frontend/sirius-components-tables/src/table/row/ResizeRowHandler.types.ts b/packages/tables/frontend/sirius-components-tables/src/rows/RowAction.types.ts similarity index 62% rename from packages/tables/frontend/sirius-components-tables/src/table/row/ResizeRowHandler.types.ts rename to packages/tables/frontend/sirius-components-tables/src/rows/RowAction.types.ts index 7647205d50..55854b9267 100644 --- a/packages/tables/frontend/sirius-components-tables/src/table/row/ResizeRowHandler.types.ts +++ b/packages/tables/frontend/sirius-components-tables/src/rows/RowAction.types.ts @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024 CEA LIST. + * Copyright (c) 2025 CEA LIST. * 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 @@ -10,19 +10,14 @@ * Contributors: * Obeo - initial API and implementation *******************************************************************************/ -import { GQLLine, GQLTable } from '../TableContent.types'; -export interface ResizeRowHandlerProps { +import { MRT_Row } from 'material-react-table'; +import { GQLLine } from '../table/TableContent.types'; + +export interface RowActionProps { editingContextId: string; representationId: string; - table: GQLTable; + tableId: string; + row: MRT_Row; readOnly: boolean; - row: GQLLine; - onRowHeightChanged: (rowId: string, height: number) => void; -} - -export interface DragState { - isDragging: boolean; - height: number; - trElement: HTMLElement | undefined; } diff --git a/packages/tables/frontend/sirius-components-tables/src/rows/RowContextMenuContent.tsx b/packages/tables/frontend/sirius-components-tables/src/rows/RowContextMenuContent.tsx new file mode 100644 index 0000000000..fa38979cd1 --- /dev/null +++ b/packages/tables/frontend/sirius-components-tables/src/rows/RowContextMenuContent.tsx @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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 + *******************************************************************************/ + +import { gql, useQuery } from '@apollo/client'; +import { IconOverlay, useMultiToast } from '@eclipse-sirius/sirius-components-core'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import ListItemText from '@mui/material/ListItemText'; +import Menu from '@mui/material/Menu'; +import MenuItem from '@mui/material/MenuItem'; +import { SxProps, Theme } from '@mui/material/styles'; +import Typography from '@mui/material/Typography'; +import { useEffect } from 'react'; +import { + GQLGetAllRowContextMenuEntriesData, + GQLGetAllRowContextMenuEntriesVariables, + GQLRepresentationDescription, + GQLRowContextMenuEntry, + GQLTableDescription, + RowContextMenuContentProps, +} from './RowContextMenuContent.types'; +import { useInvokeRowContextMenuEntry } from './useInvokeRowContextMenuEntry'; + +const getRowContextMenuEntriesQuery = gql` + query getAllRowContextMenuEntries($editingContextId: ID!, $representationId: ID!, $tableId: ID!, $rowId: ID!) { + viewer { + editingContext(editingContextId: $editingContextId) { + representation(representationId: $representationId) { + description { + __typename + ... on TableDescription { + rowContextMenuEntries(tableId: $tableId, rowId: $rowId) { + __typename + id + label + iconURLs + } + } + } + } + } + } + } +`; + +const isTableDescription = ( + gqlRepresentationDescription: GQLRepresentationDescription +): gqlRepresentationDescription is GQLTableDescription => + gqlRepresentationDescription.__typename === 'TableDescription'; + +export const RowContextMenuContent = ({ + editingContextId, + representationId, + tableId, + row, + readOnly, + anchorEl, + onClose, +}: RowContextMenuContentProps) => { + const { loading, data, error } = useQuery< + GQLGetAllRowContextMenuEntriesData, + GQLGetAllRowContextMenuEntriesVariables + >(getRowContextMenuEntriesQuery, { + variables: { + editingContextId, + representationId: tableId, + tableId, + rowId: row.original.id, + }, + }); + const { invokeRowContextMenuEntry } = useInvokeRowContextMenuEntry( + editingContextId, + representationId, + tableId, + row.original.id + ); + + const { addErrorMessage } = useMultiToast(); + + useEffect(() => { + if (error) { + const { message } = error; + addErrorMessage(message); + } + }, [error]); + + const handleClickContextMenuEntry = (menuEntry: GQLRowContextMenuEntry) => { + invokeRowContextMenuEntry(menuEntry.id); + onClose(); + }; + + const representationDescription: GQLRepresentationDescription | null = + data?.viewer.editingContext.representation?.description ?? null; + + const rowContextMenuEntries: GQLRowContextMenuEntry[] = + representationDescription && isTableDescription(representationDescription) + ? representationDescription.rowContextMenuEntries + : []; + + if (loading) { + return null; + } + + const noEntryFoundStyle: SxProps = (theme: Theme) => ({ + paddingX: theme.spacing(1), + }); + + return ( + event.stopPropagation()} + onClose={onClose} + open + data-testid={`row-context_menu-${row.original.headerLabel}`}> + {rowContextMenuEntries.length > 0 ? ( + rowContextMenuEntries.map((entry) => ( + handleClickContextMenuEntry(entry)} + data-testid={`context-menu-entry-${entry.label}`} + disabled={readOnly} + aria-disabled> + + {entry.iconURLs.length > 0 ? ( + + ) : ( +
+ )} + + + + )) + ) : ( + No entries found + )} +
+ ); +}; diff --git a/packages/tables/frontend/sirius-components-tables/src/rows/RowContextMenuContent.types.ts b/packages/tables/frontend/sirius-components-tables/src/rows/RowContextMenuContent.types.ts new file mode 100644 index 0000000000..aa38a25eb5 --- /dev/null +++ b/packages/tables/frontend/sirius-components-tables/src/rows/RowContextMenuContent.types.ts @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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 + *******************************************************************************/ + +import { MRT_Row } from 'material-react-table'; +import { GQLLine } from '../table/TableContent.types'; + +export interface RowContextMenuContentProps { + editingContextId: string; + representationId: string; + tableId: string; + row: MRT_Row; + readOnly: boolean; + anchorEl: HTMLElement | null; + onClose: () => void; +} + +export interface GQLGetAllRowContextMenuEntriesVariables { + editingContextId: string; + representationId: string; + tableId: string; + rowId: string; +} + +export interface GQLGetAllRowContextMenuEntriesData { + viewer: GQLViewer; +} + +export interface GQLViewer { + editingContext: GQLEditingContext; +} + +export interface GQLEditingContext { + representation: GQLRepresentationMetadata | null; +} + +export interface GQLRepresentationMetadata { + description: GQLRepresentationDescription; +} + +export interface GQLRepresentationDescription { + __typename: string; +} + +export interface GQLTableDescription extends GQLRepresentationDescription { + rowContextMenuEntries: GQLRowContextMenuEntry[]; +} + +export interface GQLRowContextMenuEntry { + __typename: string; + id: string; + label: string; + iconURLs: string[]; +} diff --git a/packages/tables/frontend/sirius-components-tables/src/rows/useInvokeRowContextMenuEntry.ts b/packages/tables/frontend/sirius-components-tables/src/rows/useInvokeRowContextMenuEntry.ts new file mode 100644 index 0000000000..7c349d7bec --- /dev/null +++ b/packages/tables/frontend/sirius-components-tables/src/rows/useInvokeRowContextMenuEntry.ts @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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 + *******************************************************************************/ +import { gql, useMutation } from '@apollo/client'; +import { useReporting } from '@eclipse-sirius/sirius-components-core'; +import { + GQLInvokeRowContextMenuEntryData, + GQLInvokeRowContextMenuEntryInput, + GQLInvokeRowContextMenuEntryVariables, + UseInvokeRowContextMenuEntryMutationValue, +} from './useInvokeRowContextMenuEntry.types'; + +export const invokeRowContextMenuEntryMutation = gql` + mutation invokeRowContextMenuEntry($input: InvokeRowContextMenuEntryInput!) { + invokeRowContextMenuEntry(input: $input) { + __typename + ... on ErrorPayload { + messages { + body + level + } + } + ... on SuccessPayload { + messages { + body + level + } + } + } + } +`; + +export const useInvokeRowContextMenuEntry = ( + editingContextId: string, + representationId: string, + tableId: string, + rowId: string +): UseInvokeRowContextMenuEntryMutationValue => { + const [mutationInvokeRowContextMenuEntry, mutationInvokeRowContextMenuEntryResult] = useMutation< + GQLInvokeRowContextMenuEntryData, + GQLInvokeRowContextMenuEntryVariables + >(invokeRowContextMenuEntryMutation); + useReporting( + mutationInvokeRowContextMenuEntryResult, + (data: GQLInvokeRowContextMenuEntryData) => data.invokeRowContextMenuEntry + ); + + const invokeRowContextMenuEntry = (menuEntryId: string) => { + const input: GQLInvokeRowContextMenuEntryInput = { + id: crypto.randomUUID(), + editingContextId, + representationId, + tableId, + rowId, + menuEntryId, + }; + + mutationInvokeRowContextMenuEntry({ variables: { input } }); + }; + + return { + invokeRowContextMenuEntry, + }; +}; diff --git a/packages/tables/frontend/sirius-components-tables/src/rows/useInvokeRowContextMenuEntry.types.ts b/packages/tables/frontend/sirius-components-tables/src/rows/useInvokeRowContextMenuEntry.types.ts new file mode 100644 index 0000000000..8cd7a205e3 --- /dev/null +++ b/packages/tables/frontend/sirius-components-tables/src/rows/useInvokeRowContextMenuEntry.types.ts @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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 + *******************************************************************************/ +import { GQLErrorPayload, GQLSuccessPayload } from '@eclipse-sirius/sirius-components-core'; + +export interface UseInvokeRowContextMenuEntryMutationValue { + invokeRowContextMenuEntry: (menuEntryId: string) => void; +} + +export interface GQLInvokeRowContextMenuEntryInput { + id: string; + editingContextId: string; + representationId: string; + tableId: string; + rowId: string; + menuEntryId: string; +} + +export interface GQLInvokeRowContextMenuEntryVariables { + input: GQLInvokeRowContextMenuEntryInput; +} + +export interface GQLInvokeRowContextMenuEntryData { + invokeRowContextMenuEntry: GQLInvokeRowContextMenuEntryPayload; +} + +export type GQLInvokeRowContextMenuEntryPayload = GQLErrorPayload | GQLSuccessPayload; diff --git a/packages/tables/frontend/sirius-components-tables/src/table/TableContent.tsx b/packages/tables/frontend/sirius-components-tables/src/table/TableContent.tsx index 6f705a030e..5918b00df3 100644 --- a/packages/tables/frontend/sirius-components-tables/src/table/TableContent.tsx +++ b/packages/tables/frontend/sirius-components-tables/src/table/TableContent.tsx @@ -10,7 +10,7 @@ * Contributors: * Obeo - initial API and implementation *******************************************************************************/ -import { Selection, useSelection } from '@eclipse-sirius/sirius-components-core'; +import { useSelection } from '@eclipse-sirius/sirius-components-core'; import Box from '@mui/material/Box'; import { Theme, useTheme } from '@mui/material/styles'; import { MaterialReactTable, MRT_DensityState, MRT_TableOptions, useMaterialReactTable } from 'material-react-table'; @@ -20,11 +20,10 @@ import { useTableColumnFiltering } from '../columns/useTableColumnFiltering'; import { useTableColumnOrdering } from '../columns/useTableColumnOrdering'; import { useTableColumnSizing } from '../columns/useTableColumnSizing'; import { useTableColumnVisibility } from '../columns/useTableColumnVisibility'; -import { ResizeRowHandler } from '../rows/ResizeRowHandler'; -import { RowHeader } from '../rows/RowHeader'; +import { RowAction } from '../rows/RowAction'; import { useResetRowsMutation } from '../rows/useResetRows'; import { CursorBasedPagination } from './CursorBasedPagination'; -import { GQLLine, TablePaginationState, TableProps } from './TableContent.types'; +import { GQLLine, TableContentProps, TablePaginationState } from './TableContent.types'; import { useGlobalFilter } from './useGlobalFilter'; import { useTableColumns } from './useTableColumns'; @@ -44,10 +43,14 @@ export const TableContent = memo( enableGlobalFilter, enablePagination, enableColumnOrdering, - }: TableProps) => { - const { selection, setSelection } = useSelection(); + }: TableContentProps) => { + const { selection } = useSelection(); const theme: Theme = useTheme(); + const handleRowHeightChange = (rowId: string, height: number) => { + setLinesState((prev) => prev.map((line) => (line.id === rowId ? { ...line, height } : line))); + }; + const { columns } = useTableColumns( editingContextId, representationId, @@ -56,7 +59,9 @@ export const TableContent = memo( enableColumnVisibility, enableColumnResizing, enableColumnFilters, - enableColumnOrdering + enableColumnOrdering, + enableRowSizing, + handleRowHeightChange ); const { columnSizing, setColumnSizing } = useTableColumnSizing( editingContextId, @@ -132,10 +137,6 @@ export const TableContent = memo( onPaginationChange(pagination.cursor, pagination.direction, pagination.size); }, [pagination.cursor, pagination.size, pagination.direction]); - const handleRowHeightChange = (rowId, height) => { - setLinesState((prev) => prev.map((line) => (line.id === rowId ? { ...line, height } : line))); - }; - useEffect(() => { setLinesState([...table.lines]); }, [table]); @@ -164,7 +165,11 @@ export const TableContent = memo( enableGlobalFilter, manualFiltering: true, onGlobalFilterChange: setGlobalFilter, - initialState: { showGlobalFilter: enableGlobalFilter }, + enableColumnPinning: false, + initialState: { + showGlobalFilter: enableGlobalFilter, + columnPinning: { left: ['mrt-row-header'], right: ['mrt-row-actions'] }, + }, onColumnSizingChange: setColumnSizing, onColumnVisibilityChange: setColumnVisibility, onDensityChange: setDensity, @@ -211,37 +216,14 @@ export const TableContent = memo( onPageSizeChange={handlePageSize} /> ), - displayColumnDefOptions: { - 'mrt-row-actions': { - header: '', - size: 120, - }, - }, renderRowActions: ({ row }) => ( -
{ - const newSelection: Selection = { - entries: [ - { - id: row.original.targetObjectId, - kind: row.original.targetObjectKind, - }, - ], - }; - setSelection(newSelection); - }}> - - {enableRowSizing ? ( - - ) : null} -
+ ), }; diff --git a/packages/tables/frontend/sirius-components-tables/src/table/TableContent.types.ts b/packages/tables/frontend/sirius-components-tables/src/table/TableContent.types.ts index ffdbf2ba4b..3c400670ed 100644 --- a/packages/tables/frontend/sirius-components-tables/src/table/TableContent.types.ts +++ b/packages/tables/frontend/sirius-components-tables/src/table/TableContent.types.ts @@ -12,7 +12,7 @@ *******************************************************************************/ import { GQLColumnFilter } from '../columns/useTableColumnFiltering.types'; -export interface TableProps { +export interface TableContentProps { editingContextId: string; representationId: string; table: GQLTable; diff --git a/packages/tables/frontend/sirius-components-tables/src/table/row/ResizeRowHandler.tsx b/packages/tables/frontend/sirius-components-tables/src/table/row/ResizeRowHandler.tsx deleted file mode 100644 index 1e8866fc68..0000000000 --- a/packages/tables/frontend/sirius-components-tables/src/table/row/ResizeRowHandler.tsx +++ /dev/null @@ -1,73 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2024 CEA LIST. - * 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 - *******************************************************************************/ -import { memo, useRef } from 'react'; -import { makeStyles } from 'tss-react/mui'; -import { useTableMutations } from '../../graphql/mutation/useTableMutation'; -import { DragState, ResizeRowHandlerProps } from './ResizeRowHandler.types'; - -const useStyles = makeStyles()(() => ({ - handler: { - position: 'absolute', - margin: 0, - backgroundColor: '#B3BFC5', - borderColor: '#B3BFC5', - borderRadius: '2px', - width: '24px', - height: '4px', - bottom: 0, - left: '15px', - cursor: 'row-resize', - }, -})); - -export const ResizeRowHandler = memo( - ({ editingContextId, representationId, table, readOnly, row, onRowHeightChanged }: ResizeRowHandlerProps) => { - const { classes } = useStyles(); - const { resizeRow } = useTableMutations(editingContextId, representationId, table.id); - - const dragState = useRef({ - isDragging: false, - height: 0, - trElement: undefined, - }); - - const handleMouseDown = (e) => { - e.preventDefault(); - - dragState.current = { - isDragging: true, - height: parseInt(window.getComputedStyle(e.target.parentElement.parentElement).height, 10), - trElement: e.target.parentElement.parentElement, - }; - - const handleMouseMove = (e: MouseEvent) => { - if (dragState.current.isDragging) { - dragState.current.height += e.movementY; - onRowHeightChanged(row.id, dragState.current.height); - } - }; - - const handleMouseUp = (_) => { - dragState.current.isDragging = false; - resizeRow(row.id, dragState.current.height); - document.removeEventListener('mousemove', handleMouseMove); - document.removeEventListener('mouseup', handleMouseUp); - }; - - document.addEventListener('mousemove', handleMouseMove); - document.addEventListener('mouseup', handleMouseUp); - }; - - return !readOnly && row.isResizable ?
: null; - } -); diff --git a/packages/tables/frontend/sirius-components-tables/src/table/useTableColumns.tsx b/packages/tables/frontend/sirius-components-tables/src/table/useTableColumns.tsx index d1c44f239f..b4bb7984c2 100644 --- a/packages/tables/frontend/sirius-components-tables/src/table/useTableColumns.tsx +++ b/packages/tables/frontend/sirius-components-tables/src/table/useTableColumns.tsx @@ -10,10 +10,13 @@ * Contributors: * Obeo - initial API and implementation *******************************************************************************/ +import { Selection, useSelection } from '@eclipse-sirius/sirius-components-core'; import { MRT_ColumnDef } from 'material-react-table'; import { useMemo } from 'react'; import { Cell } from '../cells/Cell'; import { ColumnHeader } from '../columns/ColumnHeader'; +import { ResizeRowHandler } from '../rows/ResizeRowHandler'; +import { RowHeader } from '../rows/RowHeader'; import { GQLCell, GQLLine, GQLTable } from './TableContent.types'; import { UseTableColumnsValue } from './useTableColumns.types'; @@ -25,8 +28,11 @@ export const useTableColumns = ( enableColumnVisibility: boolean, enableColumnSizing: boolean, enableColumnFilters: boolean, - enableColumnOrdering: boolean + enableColumnOrdering: boolean, + enableRowSizing: boolean, + handleRowHeightChange: (rowId: string, height: number) => void ): UseTableColumnsValue => { + const { setSelection } = useSelection(); const columns = useMemo[]>(() => { const columnDefs: MRT_ColumnDef[] = table.columns.map((column) => { return { @@ -57,7 +63,38 @@ export const useTableColumns = ( }; }); - return columnDefs; + const rowHeaderColumn: MRT_ColumnDef = { + id: 'mrt-row-header', + header: '', + columnDefType: 'display', + Cell: ({ row }) => ( +
{ + const newSelection: Selection = { + entries: [ + { + id: row.original.targetObjectId, + kind: row.original.targetObjectKind, + }, + ], + }; + setSelection(newSelection); + }}> + + {enableRowSizing ? ( + + ) : null} +
+ ), + }; + return [rowHeaderColumn, ...columnDefs]; }, [table]); return { diff --git a/packages/view/backend/sirius-components-view-builder/src/main/java/org/eclipse/sirius/components/view/builder/generated/table/RowContextMenuEntryBuilder.java b/packages/view/backend/sirius-components-view-builder/src/main/java/org/eclipse/sirius/components/view/builder/generated/table/RowContextMenuEntryBuilder.java new file mode 100644 index 0000000000..8f9a09ac14 --- /dev/null +++ b/packages/view/backend/sirius-components-view-builder/src/main/java/org/eclipse/sirius/components/view/builder/generated/table/RowContextMenuEntryBuilder.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2023, 2025 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.view.builder.generated.table; + +/** + * Builder for RowContextMenuEntryBuilder. + * + * @author BuilderGenerator + * @generated + */ +public class RowContextMenuEntryBuilder { + + /** + * Create instance org.eclipse.sirius.components.view.table.RowContextMenuEntry. + * @generated + */ + private org.eclipse.sirius.components.view.table.RowContextMenuEntry rowContextMenuEntry = org.eclipse.sirius.components.view.table.TableFactory.eINSTANCE.createRowContextMenuEntry(); + + /** + * Return instance org.eclipse.sirius.components.view.table.RowContextMenuEntry. + * @generated + */ + protected org.eclipse.sirius.components.view.table.RowContextMenuEntry getRowContextMenuEntry() { + return this.rowContextMenuEntry; + } + + /** + * Return instance org.eclipse.sirius.components.view.table.RowContextMenuEntry. + * @generated + */ + public org.eclipse.sirius.components.view.table.RowContextMenuEntry build() { + return this.getRowContextMenuEntry(); + } + + /** + * Setter for Name. + * + * @generated + */ + public RowContextMenuEntryBuilder name(java.lang.String value) { + this.getRowContextMenuEntry().setName(value); + return this; + } + /** + * Setter for LabelExpression. + * + * @generated + */ + public RowContextMenuEntryBuilder labelExpression(java.lang.String value) { + this.getRowContextMenuEntry().setLabelExpression(value); + return this; + } + /** + * Setter for IconURLExpression. + * + * @generated + */ + public RowContextMenuEntryBuilder iconURLExpression(java.lang.String value) { + this.getRowContextMenuEntry().setIconURLExpression(value); + return this; + } + /** + * Setter for PreconditionExpression. + * + * @generated + */ + public RowContextMenuEntryBuilder preconditionExpression(java.lang.String value) { + this.getRowContextMenuEntry().setPreconditionExpression(value); + return this; + } + /** + * Setter for Body. + * + * @generated + */ + public RowContextMenuEntryBuilder body(org.eclipse.sirius.components.view.Operation ... values) { + for (org.eclipse.sirius.components.view.Operation value : values) { + this.getRowContextMenuEntry().getBody().add(value); + } + return this; + } + + +} + diff --git a/packages/view/backend/sirius-components-view-builder/src/main/java/org/eclipse/sirius/components/view/builder/generated/table/RowDescriptionBuilder.java b/packages/view/backend/sirius-components-view-builder/src/main/java/org/eclipse/sirius/components/view/builder/generated/table/RowDescriptionBuilder.java index cff660bcc8..3f246ef92f 100644 --- a/packages/view/backend/sirius-components-view-builder/src/main/java/org/eclipse/sirius/components/view/builder/generated/table/RowDescriptionBuilder.java +++ b/packages/view/backend/sirius-components-view-builder/src/main/java/org/eclipse/sirius/components/view/builder/generated/table/RowDescriptionBuilder.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023, 2024 Obeo. + * Copyright (c) 2023, 2025 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 @@ -124,5 +124,17 @@ public RowDescriptionBuilder isResizableExpression(java.lang.String value) { return this; } + /** + * Setter for ContextMenuEntries. + * + * @generated + */ + public RowDescriptionBuilder contextMenuEntries(org.eclipse.sirius.components.view.table.RowContextMenuEntry ... values) { + for (org.eclipse.sirius.components.view.table.RowContextMenuEntry value : values) { + this.getRowDescription().getContextMenuEntries().add(value); + } + return this; + } + } diff --git a/packages/view/backend/sirius-components-view-builder/src/main/java/org/eclipse/sirius/components/view/builder/generated/table/TableBuilders.java b/packages/view/backend/sirius-components-view-builder/src/main/java/org/eclipse/sirius/components/view/builder/generated/table/TableBuilders.java index 8fdfa910e6..8bcb519388 100644 --- a/packages/view/backend/sirius-components-view-builder/src/main/java/org/eclipse/sirius/components/view/builder/generated/table/TableBuilders.java +++ b/packages/view/backend/sirius-components-view-builder/src/main/java/org/eclipse/sirius/components/view/builder/generated/table/TableBuilders.java @@ -89,5 +89,15 @@ public CellTextareaWidgetDescriptionBuilder newCellTextareaWidgetDescription() { return new CellTextareaWidgetDescriptionBuilder(); } + /** + * Instantiate a RowContextMenuEntryBuilder . + * + * @author BuilderGenerator + * @generated + */ + public RowContextMenuEntryBuilder newRowContextMenuEntry() { + return new RowContextMenuEntryBuilder(); + } + } diff --git a/packages/view/backend/sirius-components-view-emf/src/main/java/org/eclipse/sirius/components/view/emf/table/ViewRowContextMenuEntryExecutor.java b/packages/view/backend/sirius-components-view-emf/src/main/java/org/eclipse/sirius/components/view/emf/table/ViewRowContextMenuEntryExecutor.java new file mode 100644 index 0000000000..29ba77b454 --- /dev/null +++ b/packages/view/backend/sirius-components-view-emf/src/main/java/org/eclipse/sirius/components/view/emf/table/ViewRowContextMenuEntryExecutor.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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.view.emf.table; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.sirius.components.collaborative.api.ChangeKind; +import org.eclipse.sirius.components.collaborative.tables.api.IRowContextMenuEntryExecutor; +import org.eclipse.sirius.components.core.api.IEditService; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IFeedbackMessageService; +import org.eclipse.sirius.components.core.api.IObjectSearchService; +import org.eclipse.sirius.components.interpreter.AQLInterpreter; +import org.eclipse.sirius.components.representations.Failure; +import org.eclipse.sirius.components.representations.IStatus; +import org.eclipse.sirius.components.representations.Message; +import org.eclipse.sirius.components.representations.MessageLevel; +import org.eclipse.sirius.components.representations.Success; +import org.eclipse.sirius.components.representations.VariableManager; +import org.eclipse.sirius.components.tables.Line; +import org.eclipse.sirius.components.tables.Table; +import org.eclipse.sirius.components.tables.descriptions.LineDescription; +import org.eclipse.sirius.components.tables.descriptions.TableDescription; +import org.eclipse.sirius.components.view.Operation; +import org.eclipse.sirius.components.view.View; +import org.eclipse.sirius.components.view.emf.IViewRepresentationDescriptionSearchService; +import org.eclipse.sirius.components.view.emf.OperationInterpreter; +import org.eclipse.sirius.components.view.emf.ViewRepresentationDescriptionPredicate; +import org.eclipse.sirius.components.view.emf.api.IViewAQLInterpreterFactory; +import org.springframework.stereotype.Service; + +/** + * This class is in charge of delegate row context menu entry invocation for table view DSL. + * + * @author Jerome Gout + */ +@Service +public class ViewRowContextMenuEntryExecutor implements IRowContextMenuEntryExecutor { + + private final ViewRepresentationDescriptionPredicate viewRepresentationDescriptionPredicate; + + private final IViewRepresentationDescriptionSearchService viewRepresentationDescriptionSearchService; + + private final IViewAQLInterpreterFactory aqlInterpreterFactory; + + private final IFeedbackMessageService feedbackMessageService; + + private final IEditService editService; + + private final IObjectSearchService objectSearchService; + + public ViewRowContextMenuEntryExecutor(ViewRepresentationDescriptionPredicate viewRepresentationDescriptionPredicate, IViewRepresentationDescriptionSearchService viewRepresentationDescriptionSearchService, + IViewAQLInterpreterFactory aqlInterpreterFactory, IFeedbackMessageService feedbackMessageService, IEditService editService, IObjectSearchService objectSearchService) { + this.viewRepresentationDescriptionPredicate = Objects.requireNonNull(viewRepresentationDescriptionPredicate); + this.viewRepresentationDescriptionSearchService = Objects.requireNonNull(viewRepresentationDescriptionSearchService); + this.aqlInterpreterFactory = Objects.requireNonNull(aqlInterpreterFactory); + this.feedbackMessageService = Objects.requireNonNull(feedbackMessageService); + this.editService = Objects.requireNonNull(editService); + this.objectSearchService = Objects.requireNonNull(objectSearchService); + } + + @Override + public boolean canExecute(IEditingContext editingContext, TableDescription tableDescription, Table table, Line row, String rowMenuContextEntryId) { + return this.viewRepresentationDescriptionPredicate.test(tableDescription); + } + + @Override + public IStatus execute(IEditingContext editingContext, TableDescription tableDescription, Table table, Line row, String rowMenuContextEntryId) { + var optionalTableDescription = this.viewRepresentationDescriptionSearchService + .findById(editingContext, tableDescription.getId()) + .filter(org.eclipse.sirius.components.view.table.TableDescription.class::isInstance) + .map(org.eclipse.sirius.components.view.table.TableDescription.class::cast); + if (optionalTableDescription.isPresent()) { + var viewTableDescription = optionalTableDescription.get(); + + if (viewTableDescription.eContainer() instanceof View view) { + AQLInterpreter interpreter = this.aqlInterpreterFactory.createInterpreter(editingContext, view); + + VariableManager variableManager = new VariableManager(); + variableManager.put(IEditingContext.EDITING_CONTEXT, editingContext); + variableManager.put(TableDescription.TABLE, table); + variableManager.put(LineDescription.SELECTED_ROW, row); + var optionalSemanticObject = this.objectSearchService.getObject(editingContext, row.getTargetObjectId()); + if (optionalSemanticObject.isPresent()) { + var semanticObject = optionalSemanticObject.get(); + variableManager.put(VariableManager.SELF, semanticObject); + } + var contextMenuEntry = viewTableDescription.getRowDescription().getContextMenuEntries().stream() + .filter(entry -> Objects.equals(rowMenuContextEntryId, UUID.nameUUIDFromBytes(EcoreUtil.getURI(entry).toString().getBytes()).toString())) + .findFirst(); + if (contextMenuEntry.isPresent()) { + return this.executeOperations(variableManager, interpreter, contextMenuEntry.get().getBody()); + } + } + } + return this.buildFailureWithFeedbackMessages("Something went wrong while handling the context menu action"); + } + + private IStatus executeOperations(VariableManager variableManager, AQLInterpreter interpreter, List operations) { + OperationInterpreter operationInterpreter = new OperationInterpreter(interpreter, this.editService); + Optional optionalVariableManager = operationInterpreter.executeOperations(operations, variableManager); + if (optionalVariableManager.isEmpty()) { + return this.buildFailureWithFeedbackMessages("Something went wrong while handling the context menu action"); + } else { + return new Success(ChangeKind.SEMANTIC_CHANGE, Map.of(), this.feedbackMessageService.getFeedbackMessages()); + } + } + + private Failure buildFailureWithFeedbackMessages(String message) { + List errorMessages = new ArrayList<>(); + errorMessages.add(new Message(message, MessageLevel.ERROR)); + errorMessages.addAll(this.feedbackMessageService.getFeedbackMessages()); + return new Failure(errorMessages); + } +} diff --git a/packages/view/backend/sirius-components-view-emf/src/main/java/org/eclipse/sirius/components/view/emf/table/ViewRowContextMenuEntryProvider.java b/packages/view/backend/sirius-components-view-emf/src/main/java/org/eclipse/sirius/components/view/emf/table/ViewRowContextMenuEntryProvider.java new file mode 100644 index 0000000000..40050a4d4a --- /dev/null +++ b/packages/view/backend/sirius-components-view-emf/src/main/java/org/eclipse/sirius/components/view/emf/table/ViewRowContextMenuEntryProvider.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2025 CEA LIST. + * 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.view.emf.table; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.sirius.components.collaborative.tables.api.IRowContextMenuEntryProvider; +import org.eclipse.sirius.components.collaborative.tables.dto.RowContextMenuEntry; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IObjectSearchService; +import org.eclipse.sirius.components.interpreter.AQLInterpreter; +import org.eclipse.sirius.components.representations.VariableManager; +import org.eclipse.sirius.components.tables.Line; +import org.eclipse.sirius.components.tables.Table; +import org.eclipse.sirius.components.tables.descriptions.LineDescription; +import org.eclipse.sirius.components.tables.descriptions.TableDescription; +import org.eclipse.sirius.components.view.View; +import org.eclipse.sirius.components.view.emf.IViewRepresentationDescriptionSearchService; +import org.eclipse.sirius.components.view.emf.ViewRepresentationDescriptionPredicate; +import org.eclipse.sirius.components.view.emf.api.IViewAQLInterpreterFactory; +import org.springframework.stereotype.Service; + +/** + * Table row context menu entries provider for view table model. + * + * @author Jerome Gout + */ +@Service +public class ViewRowContextMenuEntryProvider implements IRowContextMenuEntryProvider { + + private final ViewRepresentationDescriptionPredicate viewRepresentationDescriptionPredicate; + + private final IViewRepresentationDescriptionSearchService viewRepresentationDescriptionSearchService; + + private final IViewAQLInterpreterFactory aqlInterpreterFactory; + + private final IObjectSearchService objectSearchService; + + public ViewRowContextMenuEntryProvider(ViewRepresentationDescriptionPredicate viewRepresentationDescriptionPredicate, + IViewRepresentationDescriptionSearchService viewRepresentationDescriptionSearchService, IViewAQLInterpreterFactory aqlInterpreterFactory, IObjectSearchService objectSearchService) { + this.viewRepresentationDescriptionPredicate = Objects.requireNonNull(viewRepresentationDescriptionPredicate); + this.viewRepresentationDescriptionSearchService = Objects.requireNonNull(viewRepresentationDescriptionSearchService); + this.aqlInterpreterFactory = Objects.requireNonNull(aqlInterpreterFactory); + this.objectSearchService = Objects.requireNonNull(objectSearchService); + } + + @Override + public boolean canHandle(IEditingContext editingContext, TableDescription tableDescription, Table table, Line row) { + return this.viewRepresentationDescriptionPredicate.test(tableDescription); + } + + @Override + public List getRowContextMenuEntries(IEditingContext editingContext, TableDescription tableDescription, Table table, Line row) { + var optionalTableDescription = this.viewRepresentationDescriptionSearchService + .findById(editingContext, tableDescription.getId()) + .filter(org.eclipse.sirius.components.view.table.TableDescription.class::isInstance) + .map(org.eclipse.sirius.components.view.table.TableDescription.class::cast); + if (optionalTableDescription.isPresent()) { + var viewTableDescription = optionalTableDescription.get(); + + if (viewTableDescription.eContainer() instanceof View view) { + AQLInterpreter interpreter = this.aqlInterpreterFactory.createInterpreter(editingContext, view); + + VariableManager variableManager = new VariableManager(); + variableManager.put(IEditingContext.EDITING_CONTEXT, editingContext); + variableManager.put(TableDescription.TABLE, table); + variableManager.put(LineDescription.SELECTED_ROW, row); + var optionalSemanticObject = this.objectSearchService.getObject(editingContext, row.getTargetObjectId()); + if (optionalSemanticObject.isPresent()) { + var semanticObject = optionalSemanticObject.get(); + variableManager.put(VariableManager.SELF, semanticObject); + } + return viewTableDescription.getRowDescription().getContextMenuEntries().stream() + .filter(viewAction -> this.evaluateBoolean(variableManager, interpreter, viewAction.getPreconditionExpression())) + .map(rowContextMenuEntry -> this.convertContextAction(rowContextMenuEntry, variableManager, interpreter)) + .toList(); + } + } + return List.of(); + } + + private RowContextMenuEntry convertContextAction(org.eclipse.sirius.components.view.table.RowContextMenuEntry viewTreeItemContextAction, VariableManager variableManager, + AQLInterpreter interpreter) { + var id = UUID.nameUUIDFromBytes(EcoreUtil.getURI(viewTreeItemContextAction).toString().getBytes()).toString(); + var label = this.evaluateString(variableManager, interpreter, viewTreeItemContextAction.getLabelExpression()); + var iconURL = this.evaluateStringList(variableManager, interpreter, viewTreeItemContextAction.getIconURLExpression()); + + return new RowContextMenuEntry(id, label, iconURL); + } + + private String evaluateString(VariableManager variableManager, AQLInterpreter interpreter, String expression) { + return interpreter.evaluateExpression(variableManager.getVariables(), expression) + .asString() + .orElse(""); + } + + private List evaluateStringList(VariableManager variableManager, AQLInterpreter interpreter, String expression) { + List objects = interpreter.evaluateExpression(variableManager.getVariables(), expression).asObjects().orElse(List.of()); + return objects.stream() + .filter(String.class::isInstance) + .map(String.class::cast) + .toList(); + } + + private Boolean evaluateBoolean(VariableManager variableManager, AQLInterpreter interpreter, String expression) { + return interpreter.evaluateExpression(variableManager.getVariables(), expression) + .asBoolean() + .orElse(true); + } +} diff --git a/packages/view/backend/sirius-components-view-table-edit/src/main/java/org/eclipse/sirius/components/view/table/provider/RowContextMenuEntryItemProvider.java b/packages/view/backend/sirius-components-view-table-edit/src/main/java/org/eclipse/sirius/components/view/table/provider/RowContextMenuEntryItemProvider.java new file mode 100644 index 0000000000..60a318f4e3 --- /dev/null +++ b/packages/view/backend/sirius-components-view-table-edit/src/main/java/org/eclipse/sirius/components/view/table/provider/RowContextMenuEntryItemProvider.java @@ -0,0 +1,278 @@ +/******************************************************************************* + * Copyright (c) 2025, 2025 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.view.table.provider; + +import java.util.Collection; +import java.util.List; + +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.util.ResourceLocator; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.edit.provider.ComposeableAdapterFactory; +import org.eclipse.emf.edit.provider.IChildCreationExtender; +import org.eclipse.emf.edit.provider.IEditingDomainItemProvider; +import org.eclipse.emf.edit.provider.IItemLabelProvider; +import org.eclipse.emf.edit.provider.IItemPropertyDescriptor; +import org.eclipse.emf.edit.provider.IItemPropertySource; +import org.eclipse.emf.edit.provider.IStructuredItemContentProvider; +import org.eclipse.emf.edit.provider.ITreeItemContentProvider; +import org.eclipse.emf.edit.provider.ItemPropertyDescriptor; +import org.eclipse.emf.edit.provider.ItemProviderAdapter; +import org.eclipse.emf.edit.provider.ViewerNotification; +import org.eclipse.sirius.components.view.ViewFactory; +import org.eclipse.sirius.components.view.table.RowContextMenuEntry; +import org.eclipse.sirius.components.view.table.TablePackage; + +/** + * This is the item provider adapter for a + * {@link org.eclipse.sirius.components.view.table.RowContextMenuEntry} object. + * + * + * @generated + */ +public class RowContextMenuEntryItemProvider extends ItemProviderAdapter implements IEditingDomainItemProvider, + IStructuredItemContentProvider, ITreeItemContentProvider, IItemLabelProvider, IItemPropertySource { + + /** + * This constructs an instance from a factory and a notifier. + * + * @generated + */ + public RowContextMenuEntryItemProvider(AdapterFactory adapterFactory) { + super(adapterFactory); + } + + /** + * This returns the property descriptors for the adapted class. + * + * @generated + */ + @Override + public List getPropertyDescriptors(Object object) { + if (this.itemPropertyDescriptors == null) { + super.getPropertyDescriptors(object); + + this.addNamePropertyDescriptor(object); + this.addLabelExpressionPropertyDescriptor(object); + this.addIconURLExpressionPropertyDescriptor(object); + this.addPreconditionExpressionPropertyDescriptor(object); + } + return this.itemPropertyDescriptors; + } + + /** + * This adds a property descriptor for the Name feature. + * + * + * @generated + */ + protected void addNamePropertyDescriptor(Object object) { + this.itemPropertyDescriptors + .add(this.createItemPropertyDescriptor(((ComposeableAdapterFactory) this.adapterFactory).getRootAdapterFactory(), + this.getResourceLocator(), this.getString("_UI_RowContextMenuEntry_name_feature"), + this.getString("_UI_PropertyDescriptor_description", "_UI_RowContextMenuEntry_name_feature", + "_UI_RowContextMenuEntry_type"), + TablePackage.Literals.ROW_CONTEXT_MENU_ENTRY__NAME, true, false, false, + ItemPropertyDescriptor.GENERIC_VALUE_IMAGE, null, null)); + } + + /** + * This adds a property descriptor for the Label Expression feature. + * + * @generated + */ + protected void addLabelExpressionPropertyDescriptor(Object object) { + this.itemPropertyDescriptors.add(this.createItemPropertyDescriptor( + ((ComposeableAdapterFactory) this.adapterFactory).getRootAdapterFactory(), this.getResourceLocator(), + this.getString("_UI_RowContextMenuEntry_labelExpression_feature"), + this.getString("_UI_PropertyDescriptor_description", "_UI_RowContextMenuEntry_labelExpression_feature", + "_UI_RowContextMenuEntry_type"), + TablePackage.Literals.ROW_CONTEXT_MENU_ENTRY__LABEL_EXPRESSION, true, false, false, + ItemPropertyDescriptor.GENERIC_VALUE_IMAGE, null, null)); + } + + /** + * This adds a property descriptor for the Icon URL Expression feature. + * + * @generated + */ + protected void addIconURLExpressionPropertyDescriptor(Object object) { + this.itemPropertyDescriptors + .add(this.createItemPropertyDescriptor(((ComposeableAdapterFactory) this.adapterFactory).getRootAdapterFactory(), + this.getResourceLocator(), this.getString("_UI_RowContextMenuEntry_iconURLExpression_feature"), + this.getString("_UI_PropertyDescriptor_description", + "_UI_RowContextMenuEntry_iconURLExpression_feature", "_UI_RowContextMenuEntry_type"), + TablePackage.Literals.ROW_CONTEXT_MENU_ENTRY__ICON_URL_EXPRESSION, true, false, false, + ItemPropertyDescriptor.GENERIC_VALUE_IMAGE, null, null)); + } + + /** + * This adds a property descriptor for the Precondition Expression feature. + * + * @generated + */ + protected void addPreconditionExpressionPropertyDescriptor(Object object) { + this.itemPropertyDescriptors.add(this.createItemPropertyDescriptor( + ((ComposeableAdapterFactory) this.adapterFactory).getRootAdapterFactory(), this.getResourceLocator(), + this.getString("_UI_RowContextMenuEntry_preconditionExpression_feature"), + this.getString("_UI_PropertyDescriptor_description", + "_UI_RowContextMenuEntry_preconditionExpression_feature", "_UI_RowContextMenuEntry_type"), + TablePackage.Literals.ROW_CONTEXT_MENU_ENTRY__PRECONDITION_EXPRESSION, 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 + * {@link org.eclipse.emf.edit.command.MoveCommand} in {@link #createCommand}. + * + * + * @generated + */ + @Override + public Collection getChildrenFeatures(Object object) { + if (this.childrenFeatures == null) { + super.getChildrenFeatures(object); + this.childrenFeatures.add(TablePackage.Literals.ROW_CONTEXT_MENU_ENTRY__BODY); + } + return this.childrenFeatures; + } + + /** + * + * + * @generated + */ + @Override + protected EStructuralFeature getChildFeature(Object object, Object child) { + // Check the type of the specified child object and return the proper feature to + // use for + // adding (see {@link AddCommand}) it as a child. + + return super.getChildFeature(object, child); + } + + /** + * This returns RowContextMenuEntry.gif. + * + * @generated + */ + @Override + public Object getImage(Object object) { + return this.overlayImage(object, this.getResourceLocator().getImage("full/obj16/RowContextMenuEntry")); + } + + /** + * + * + * @generated + */ + @Override + protected boolean shouldComposeCreationImage() { + return true; + } + + /** + * This returns the label text for the adapted class. + * + * + * @generated + */ + @Override + public String getText(Object object) { + String label = ((RowContextMenuEntry) object).getName(); + return label == null || label.length() == 0 ? this.getString("_UI_RowContextMenuEntry_type") + : this.getString("_UI_RowContextMenuEntry_type") + " " + label; + } + + /** + * This handles model notifications by calling {@link #updateChildren} to update + * any cached children and by creating a viewer notification, which it passes to + * {@link #fireNotifyChanged}. + * + * @generated + */ + @Override + public void notifyChanged(Notification notification) { + this.updateChildren(notification); + + switch (notification.getFeatureID(RowContextMenuEntry.class)) { + case TablePackage.ROW_CONTEXT_MENU_ENTRY__NAME: + case TablePackage.ROW_CONTEXT_MENU_ENTRY__LABEL_EXPRESSION: + case TablePackage.ROW_CONTEXT_MENU_ENTRY__ICON_URL_EXPRESSION: + case TablePackage.ROW_CONTEXT_MENU_ENTRY__PRECONDITION_EXPRESSION: + this.fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), false, true)); + return; + case TablePackage.ROW_CONTEXT_MENU_ENTRY__BODY: + this.fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false)); + return; + } + super.notifyChanged(notification); + } + + /** + * This adds {@link org.eclipse.emf.edit.command.CommandParameter}s describing + * the children that can be created under this object. + * + * + * @generated + */ + @Override + protected void collectNewChildDescriptors(Collection newChildDescriptors, Object object) { + super.collectNewChildDescriptors(newChildDescriptors, object); + + newChildDescriptors.add(this.createChildParameter(TablePackage.Literals.ROW_CONTEXT_MENU_ENTRY__BODY, + ViewFactory.eINSTANCE.createChangeContext())); + + newChildDescriptors.add(this.createChildParameter(TablePackage.Literals.ROW_CONTEXT_MENU_ENTRY__BODY, + ViewFactory.eINSTANCE.createCreateInstance())); + + newChildDescriptors.add(this.createChildParameter(TablePackage.Literals.ROW_CONTEXT_MENU_ENTRY__BODY, + ViewFactory.eINSTANCE.createSetValue())); + + newChildDescriptors.add(this.createChildParameter(TablePackage.Literals.ROW_CONTEXT_MENU_ENTRY__BODY, + ViewFactory.eINSTANCE.createUnsetValue())); + + newChildDescriptors.add(this.createChildParameter(TablePackage.Literals.ROW_CONTEXT_MENU_ENTRY__BODY, + ViewFactory.eINSTANCE.createDeleteElement())); + + newChildDescriptors.add(this.createChildParameter(TablePackage.Literals.ROW_CONTEXT_MENU_ENTRY__BODY, + ViewFactory.eINSTANCE.createLet())); + + newChildDescriptors.add(this.createChildParameter(TablePackage.Literals.ROW_CONTEXT_MENU_ENTRY__BODY, + ViewFactory.eINSTANCE.createIf())); + + newChildDescriptors.add(this.createChildParameter(TablePackage.Literals.ROW_CONTEXT_MENU_ENTRY__BODY, + ViewFactory.eINSTANCE.createFor())); + } + + /** + * Return the resource locator for this item provider's resources. + * + * @generated + */ + @Override + public ResourceLocator getResourceLocator() { + return ((IChildCreationExtender) this.adapterFactory).getResourceLocator(); + } + +} diff --git a/packages/view/backend/sirius-components-view-table-edit/src/main/java/org/eclipse/sirius/components/view/table/provider/RowDescriptionItemProvider.java b/packages/view/backend/sirius-components-view-table-edit/src/main/java/org/eclipse/sirius/components/view/table/provider/RowDescriptionItemProvider.java index 0e302117b2..07d0fe7099 100644 --- a/packages/view/backend/sirius-components-view-table-edit/src/main/java/org/eclipse/sirius/components/view/table/provider/RowDescriptionItemProvider.java +++ b/packages/view/backend/sirius-components-view-table-edit/src/main/java/org/eclipse/sirius/components/view/table/provider/RowDescriptionItemProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024 CEA LIST. + * Copyright (c) 2024, 2025 CEA LIST. * 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 @@ -17,11 +17,13 @@ import org.eclipse.emf.common.notify.AdapterFactory; import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.edit.provider.ComposeableAdapterFactory; import org.eclipse.emf.edit.provider.IItemPropertyDescriptor; import org.eclipse.emf.edit.provider.ItemPropertyDescriptor; import org.eclipse.emf.edit.provider.ViewerNotification; import org.eclipse.sirius.components.view.table.RowDescription; +import org.eclipse.sirius.components.view.table.TableFactory; import org.eclipse.sirius.components.view.table.TablePackage; /** @@ -143,6 +145,38 @@ protected void addIsResizableExpressionPropertyDescriptor(Object object) { 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 + * {@link org.eclipse.emf.edit.command.MoveCommand} in {@link #createCommand}. + * + * + * @generated + */ + @Override + public Collection getChildrenFeatures(Object object) { + if (this.childrenFeatures == null) { + super.getChildrenFeatures(object); + this.childrenFeatures.add(TablePackage.Literals.ROW_DESCRIPTION__CONTEXT_MENU_ENTRIES); + } + return this.childrenFeatures; + } + + /** + * + * + * @generated + */ + @Override + protected EStructuralFeature getChildFeature(Object object, Object child) { + // Check the type of the specified child object and return the proper feature to + // use for + // adding (see {@link AddCommand}) it as a child. + + return super.getChildFeature(object, child); + } + /** * This returns RowDescription.gif. @@ -196,6 +230,9 @@ public void notifyChanged(Notification notification) { case TablePackage.ROW_DESCRIPTION__IS_RESIZABLE_EXPRESSION: this.fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), false, true)); return; + case TablePackage.ROW_DESCRIPTION__CONTEXT_MENU_ENTRIES: + this.fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false)); + return; } super.notifyChanged(notification); } @@ -210,6 +247,9 @@ public void notifyChanged(Notification notification) { @Override protected void collectNewChildDescriptors(Collection newChildDescriptors, Object object) { super.collectNewChildDescriptors(newChildDescriptors, object); + + newChildDescriptors.add(this.createChildParameter(TablePackage.Literals.ROW_DESCRIPTION__CONTEXT_MENU_ENTRIES, + TableFactory.eINSTANCE.createRowContextMenuEntry())); } } diff --git a/packages/view/backend/sirius-components-view-table-edit/src/main/java/org/eclipse/sirius/components/view/table/provider/TableItemProviderAdapterFactory.java b/packages/view/backend/sirius-components-view-table-edit/src/main/java/org/eclipse/sirius/components/view/table/provider/TableItemProviderAdapterFactory.java index b78f370395..e7293e299c 100644 --- a/packages/view/backend/sirius-components-view-table-edit/src/main/java/org/eclipse/sirius/components/view/table/provider/TableItemProviderAdapterFactory.java +++ b/packages/view/backend/sirius-components-view-table-edit/src/main/java/org/eclipse/sirius/components/view/table/provider/TableItemProviderAdapterFactory.java @@ -139,6 +139,14 @@ public class TableItemProviderAdapterFactory extends TableAdapterFactory * @generated */ protected CellLabelWidgetDescriptionItemProvider cellLabelWidgetDescriptionItemProvider; + /** + * This keeps track of the one adapter used for all + * {@link org.eclipse.sirius.components.view.table.RowContextMenuEntry} + * instances. + * + * @generated + */ + protected RowContextMenuEntryItemProvider rowContextMenuEntryItemProvider; /** * This keeps track of the one adapter used for all @@ -273,6 +281,22 @@ public Adapter createCellTextareaWidgetDescriptionAdapter() { return this.cellTextareaWidgetDescriptionItemProvider; } + /** + * This creates an adapter for a + * {@link org.eclipse.sirius.components.view.table.RowContextMenuEntry}. + * + * @generated + */ + @Override + public Adapter createRowContextMenuEntryAdapter() { + if (this.rowContextMenuEntryItemProvider == null) { + this.rowContextMenuEntryItemProvider = new RowContextMenuEntryItemProvider(this); + } + + return this.rowContextMenuEntryItemProvider; + } + /** * This returns the root adapter factory that contains this factory. @@ -417,6 +441,8 @@ public void dispose() { this.cellLabelWidgetDescriptionItemProvider.dispose(); if (this.cellTextareaWidgetDescriptionItemProvider != null) this.cellTextareaWidgetDescriptionItemProvider.dispose(); + if (this.rowContextMenuEntryItemProvider != null) + this.rowContextMenuEntryItemProvider.dispose(); } /** diff --git a/packages/view/backend/sirius-components-view-table-edit/src/main/resources/icons/full/obj16/RowContextMenuEntry.svg b/packages/view/backend/sirius-components-view-table-edit/src/main/resources/icons/full/obj16/RowContextMenuEntry.svg new file mode 100644 index 0000000000..e87fea7d03 --- /dev/null +++ b/packages/view/backend/sirius-components-view-table-edit/src/main/resources/icons/full/obj16/RowContextMenuEntry.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/view/backend/sirius-components-view-table-edit/src/main/resources/plugin.properties b/packages/view/backend/sirius-components-view-table-edit/src/main/resources/plugin.properties index ad32873d3d..66c1e25545 100644 --- a/packages/view/backend/sirius-components-view-table-edit/src/main/resources/plugin.properties +++ b/packages/view/backend/sirius-components-view-table-edit/src/main/resources/plugin.properties @@ -32,6 +32,7 @@ _UI_CellWidgetDescription_type=Cell Widget Description _UI_CellTextfieldWidgetDescription_type=Cell Textfield Widget Description _UI_CellLabelWidgetDescription_type=Cell Label Widget Description _UI_CellTextareaWidgetDescription_type=Cell Textarea Widget Description +_UI_RowContextMenuEntry_type=Row Context Menu Entry _UI_Unknown_type=Object _UI_Unknown_datatype=Value @@ -55,10 +56,16 @@ _UI_RowDescription_headerIconExpression_feature=Header Icon Expression _UI_RowDescription_headerIndexLabelExpression_feature=Header Index Label Expression _UI_RowDescription_initialHeightExpression_feature=Initial Height Expression _UI_RowDescription_isResizableExpression_feature=Is Resizable Expression +_UI_RowDescription_contextMenuEntries_feature=Context Menu Entries _UI_CellDescription_valueExpression_feature=Value Expression _UI_CellDescription_tooltipExpression_feature=Tooltip Expression _UI_CellDescription_cellWidgetDescription_feature=Cell Widget Description _UI_CellTextfieldWidgetDescription_body_feature=Body _UI_CellLabelWidgetDescription_iconExpression_feature=Icon Expression _UI_CellTextareaWidgetDescription_body_feature=Body +_UI_RowContextMenuEntry_name_feature=Name +_UI_RowContextMenuEntry_labelExpression_feature=Label Expression +_UI_RowContextMenuEntry_iconURLExpression_feature=Icon URL Expression +_UI_RowContextMenuEntry_preconditionExpression_feature=Precondition Expression +_UI_RowContextMenuEntry_body_feature=Body _UI_Unknown_feature=Unspecified diff --git a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/RowContextMenuEntry.java b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/RowContextMenuEntry.java new file mode 100644 index 0000000000..92c2eae055 --- /dev/null +++ b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/RowContextMenuEntry.java @@ -0,0 +1,146 @@ +/******************************************************************************* + * Copyright (c) 2025, 2025 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.view.table; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.sirius.components.view.Operation; + +/** + * A representation of the model object 'Row Context Menu Entry'. + * + *

+ * The following features are supported: + *

+ *
    + *
  • {@link org.eclipse.sirius.components.view.table.RowContextMenuEntry#getName Name}
  • + *
  • {@link org.eclipse.sirius.components.view.table.RowContextMenuEntry#getLabelExpression Label + * Expression}
  • + *
  • {@link org.eclipse.sirius.components.view.table.RowContextMenuEntry#getIconURLExpression Icon URL + * Expression}
  • + *
  • {@link org.eclipse.sirius.components.view.table.RowContextMenuEntry#getPreconditionExpression Precondition + * Expression}
  • + *
  • {@link org.eclipse.sirius.components.view.table.RowContextMenuEntry#getBody Body}
  • + *
+ * + * @model + * @generated + * @see org.eclipse.sirius.components.view.table.TablePackage#getRowContextMenuEntry() + */ +public interface RowContextMenuEntry extends EObject { + + /** + * Returns the value of the 'Name' attribute. + * + * @return the value of the 'Name' attribute. + * @model dataType="org.eclipse.sirius.components.view.Identifier" required="true" + * @generated + * @see #setName(String) + * @see org.eclipse.sirius.components.view.table.TablePackage#getRowContextMenuEntry_Name() + */ + String getName(); + + /** + * Sets the value of the '{@link org.eclipse.sirius.components.view.table.RowContextMenuEntry#getName + * Name}' attribute. + * + * @param value + * the new value of the 'Name' attribute. + * @generated + * @see #getName() + */ + void setName(String value); + + /** + * Returns the value of the 'Label Expression' attribute. + * + * @return the value of the 'Label Expression' attribute. + * @model dataType="org.eclipse.sirius.components.view.InterpretedExpression" + * @generated + * @see #setLabelExpression(String) + * @see org.eclipse.sirius.components.view.table.TablePackage#getRowContextMenuEntry_LabelExpression() + */ + String getLabelExpression(); + + /** + * Sets the value of the '{@link org.eclipse.sirius.components.view.table.RowContextMenuEntry#getLabelExpression + * Label Expression}' attribute. + * + * @param value + * the new value of the 'Label Expression' attribute. + * @generated + * @see #getLabelExpression() + */ + void setLabelExpression(String value); + + /** + * Returns the value of the 'Icon URL Expression' attribute. + * + * @return the value of the 'Icon URL Expression' attribute. + * @model dataType="org.eclipse.sirius.components.view.InterpretedExpression" + * @generated + * @see #setIconURLExpression(String) + * @see org.eclipse.sirius.components.view.table.TablePackage#getRowContextMenuEntry_IconURLExpression() + */ + String getIconURLExpression(); + + /** + * Sets the value of the '{@link org.eclipse.sirius.components.view.table.RowContextMenuEntry#getIconURLExpression + * Icon URL Expression}' attribute. + * + * @param value + * the new value of the 'Icon URL Expression' attribute. + * @generated + * @see #getIconURLExpression() + */ + void setIconURLExpression(String value); + + /** + * Returns the value of the 'Precondition Expression' attribute. + * + * @return the value of the 'Precondition Expression' attribute. + * @model dataType="org.eclipse.sirius.components.view.InterpretedExpression" + * @generated + * @see #setPreconditionExpression(String) + * @see org.eclipse.sirius.components.view.table.TablePackage#getRowContextMenuEntry_PreconditionExpression() + */ + String getPreconditionExpression(); + + /** + * Sets the value of the + * '{@link org.eclipse.sirius.components.view.table.RowContextMenuEntry#getPreconditionExpression Precondition + * Expression}' attribute. + * + * @param value + * the new value of the 'Precondition Expression' attribute. + * @generated + * @see #getPreconditionExpression() + */ + void setPreconditionExpression(String value); + + /** + * Returns the value of the 'Body' containment reference list. The list contents are of type + * {@link org.eclipse.sirius.components.view.Operation}. + * + * @return the value of the 'Body' containment reference list. + * @model containment="true" + * @generated + * @see org.eclipse.sirius.components.view.table.TablePackage#getRowContextMenuEntry_Body() + */ + EList getBody(); + +} // RowContextMenuEntry diff --git a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/RowDescription.java b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/RowDescription.java index 51e603f956..a1c5a91d24 100644 --- a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/RowDescription.java +++ b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/RowDescription.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024 CEA LIST. + * Copyright (c) 2024, 2025 CEA LIST. * 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 @@ -12,6 +12,8 @@ *******************************************************************************/ package org.eclipse.sirius.components.view.table; +import org.eclipse.emf.common.util.EList; + /** * A representation of the model object 'Row Description'. * @@ -29,11 +31,13 @@ * Expression} *
  • {@link org.eclipse.sirius.components.view.table.RowDescription#getIsResizableExpression Is Resizable * Expression}
  • + *
  • {@link org.eclipse.sirius.components.view.table.RowDescription#getContextMenuEntries Context Menu + * Entries}
  • * * + * @see org.eclipse.sirius.components.view.table.TablePackage#getRowDescription() * @model * @generated - * @see org.eclipse.sirius.components.view.table.TablePackage#getRowDescription() */ public interface RowDescription extends TableElementDescription { @@ -42,10 +46,10 @@ public interface RowDescription extends TableElementDescription { * "". * * @return the value of the 'Header Label Expression' attribute. - * @model default="" dataType="org.eclipse.sirius.components.view.InterpretedExpression" - * @generated * @see #setHeaderLabelExpression(String) * @see org.eclipse.sirius.components.view.table.TablePackage#getRowDescription_HeaderLabelExpression() + * @model default="" dataType="org.eclipse.sirius.components.view.InterpretedExpression" + * @generated */ String getHeaderLabelExpression(); @@ -54,9 +58,9 @@ public interface RowDescription extends TableElementDescription { * Header Label Expression}' attribute. * * @param value - * the new value of the 'Header Label Expression' attribute. - * @generated + * the new value of the 'Header Label Expression' attribute. * @see #getHeaderLabelExpression() + * @generated */ void setHeaderLabelExpression(String value); @@ -65,10 +69,10 @@ public interface RowDescription extends TableElementDescription { * "". * * @return the value of the 'Header Icon Expression' attribute. - * @model default="" dataType="org.eclipse.sirius.components.view.InterpretedExpression" - * @generated * @see #setHeaderIconExpression(String) * @see org.eclipse.sirius.components.view.table.TablePackage#getRowDescription_HeaderIconExpression() + * @model default="" dataType="org.eclipse.sirius.components.view.InterpretedExpression" + * @generated */ String getHeaderIconExpression(); @@ -77,9 +81,9 @@ public interface RowDescription extends TableElementDescription { * Header Icon Expression}' attribute. * * @param value - * the new value of the 'Header Icon Expression' attribute. - * @generated + * the new value of the 'Header Icon Expression' attribute. * @see #getHeaderIconExpression() + * @generated */ void setHeaderIconExpression(String value); @@ -88,10 +92,10 @@ public interface RowDescription extends TableElementDescription { * end-user-doc --> * * @return the value of the 'Header Index Label Expression' attribute. - * @model dataType="org.eclipse.sirius.components.view.InterpretedExpression" - * @generated * @see #setHeaderIndexLabelExpression(String) * @see org.eclipse.sirius.components.view.table.TablePackage#getRowDescription_HeaderIndexLabelExpression() + * @model dataType="org.eclipse.sirius.components.view.InterpretedExpression" + * @generated */ String getHeaderIndexLabelExpression(); @@ -101,9 +105,9 @@ public interface RowDescription extends TableElementDescription { * Label Expression}' attribute. * * @param value - * the new value of the 'Header Index Label Expression' attribute. - * @generated + * the new value of the 'Header Index Label Expression' attribute. * @see #getHeaderIndexLabelExpression() + * @generated */ void setHeaderIndexLabelExpression(String value); @@ -112,10 +116,10 @@ public interface RowDescription extends TableElementDescription { * "". * * @return the value of the 'Initial Height Expression' attribute. - * @model default="" dataType="org.eclipse.sirius.components.view.InterpretedExpression" - * @generated * @see #setInitialHeightExpression(String) * @see org.eclipse.sirius.components.view.table.TablePackage#getRowDescription_InitialHeightExpression() + * @model default="" dataType="org.eclipse.sirius.components.view.InterpretedExpression" + * @generated */ String getInitialHeightExpression(); @@ -124,9 +128,9 @@ public interface RowDescription extends TableElementDescription { * Initial Height Expression}' attribute. * * @param value - * the new value of the 'Initial Height Expression' attribute. - * @generated + * the new value of the 'Initial Height Expression' attribute. * @see #getInitialHeightExpression() + * @generated */ void setInitialHeightExpression(String value); @@ -135,10 +139,10 @@ public interface RowDescription extends TableElementDescription { * "". * * @return the value of the 'Is Resizable Expression' attribute. - * @model default="" dataType="org.eclipse.sirius.components.view.InterpretedExpression" - * @generated * @see #setIsResizableExpression(String) * @see org.eclipse.sirius.components.view.table.TablePackage#getRowDescription_IsResizableExpression() + * @model default="" dataType="org.eclipse.sirius.components.view.InterpretedExpression" + * @generated */ String getIsResizableExpression(); @@ -147,10 +151,22 @@ public interface RowDescription extends TableElementDescription { * Is Resizable Expression}' attribute. * * @param value - * the new value of the 'Is Resizable Expression' attribute. - * @generated + * the new value of the 'Is Resizable Expression' attribute. * @see #getIsResizableExpression() + * @generated */ void setIsResizableExpression(String value); + /** + * Returns the value of the 'Context Menu Entries' containment reference list. The list contents are + * of type {@link org.eclipse.sirius.components.view.table.RowContextMenuEntry}. + * + * @return the value of the 'Context Menu Entries' containment reference list. + * @see org.eclipse.sirius.components.view.table.TablePackage#getRowDescription_ContextMenuEntries() + * @model containment="true" + * @generated + */ + EList getContextMenuEntries(); + } // RowDescription diff --git a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/TableFactory.java b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/TableFactory.java index 0667961a58..2147f55acd 100644 --- a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/TableFactory.java +++ b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/TableFactory.java @@ -89,6 +89,14 @@ public interface TableFactory extends EFactory { */ CellTextareaWidgetDescription createCellTextareaWidgetDescription(); + /** + * Returns a new object of class 'Row Context Menu Entry'. + * + * @return a new object of class 'Row Context Menu Entry'. + * @generated + */ + RowContextMenuEntry createRowContextMenuEntry(); + /** * Returns the package supported by this factory. * diff --git a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/TablePackage.java b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/TablePackage.java index 34207b3977..53db3925ac 100644 --- a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/TablePackage.java +++ b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/TablePackage.java @@ -428,6 +428,15 @@ public interface TablePackage extends EPackage { */ int ROW_DESCRIPTION__IS_RESIZABLE_EXPRESSION = TABLE_ELEMENT_DESCRIPTION_FEATURE_COUNT + 4; + /** + * The feature id for the 'Context Menu Entries' containment reference list. + * + * + * @generated + * @ordered + */ + int ROW_DESCRIPTION__CONTEXT_MENU_ENTRIES = TABLE_ELEMENT_DESCRIPTION_FEATURE_COUNT + 5; + /** * The number of structural features of the 'Row Description' class. @@ -435,7 +444,7 @@ public interface TablePackage extends EPackage { * @generated * @ordered */ - int ROW_DESCRIPTION_FEATURE_COUNT = TABLE_ELEMENT_DESCRIPTION_FEATURE_COUNT + 5; + int ROW_DESCRIPTION_FEATURE_COUNT = TABLE_ELEMENT_DESCRIPTION_FEATURE_COUNT + 6; /** * The number of operations of the 'Row Description' class. @@ -616,31 +625,93 @@ public interface TablePackage extends EPackage { * @ordered */ int CELL_LABEL_WIDGET_DESCRIPTION__ICON_EXPRESSION = CELL_WIDGET_DESCRIPTION_FEATURE_COUNT; - + /** + * The number of structural features of the 'Cell Label Widget Description' class. + * + * + * @generated + * @ordered + */ + int CELL_LABEL_WIDGET_DESCRIPTION_FEATURE_COUNT = CELL_WIDGET_DESCRIPTION_FEATURE_COUNT + 1; + /** + * The number of operations of the 'Cell Label Widget Description' class. + * + * @generated + * @ordered + */ + int CELL_LABEL_WIDGET_DESCRIPTION_OPERATION_COUNT = CELL_WIDGET_DESCRIPTION_OPERATION_COUNT; + /** + * The meta object id for the '{@link org.eclipse.sirius.components.view.table.impl.RowContextMenuEntryImpl Row + * Context Menu Entry}' class. + * + * @generated + * @see org.eclipse.sirius.components.view.table.impl.RowContextMenuEntryImpl + * @see org.eclipse.sirius.components.view.table.impl.TablePackageImpl#getRowContextMenuEntry() + */ + int ROW_CONTEXT_MENU_ENTRY = 8; + /** + * The feature id for the 'Name' attribute. + * + * @generated + * @ordered + */ + int ROW_CONTEXT_MENU_ENTRY__NAME = 0; + /** + * The feature id for the 'Label Expression' attribute. + * + * @generated + * @ordered + */ + int ROW_CONTEXT_MENU_ENTRY__LABEL_EXPRESSION = 1; + /** + * The feature id for the 'Icon URL Expression' attribute. + * + * @generated + * @ordered + */ + int ROW_CONTEXT_MENU_ENTRY__ICON_URL_EXPRESSION = 2; + /** + * The feature id for the 'Precondition Expression' attribute. + * + * @generated + * @ordered + */ + int ROW_CONTEXT_MENU_ENTRY__PRECONDITION_EXPRESSION = 3; + /** + * The feature id for the 'Body' containment reference list. + * + * @generated + * @ordered + */ + int ROW_CONTEXT_MENU_ENTRY__BODY = 4; /** * The singleton instance of the package. * * @generated */ TablePackage eINSTANCE = org.eclipse.sirius.components.view.table.impl.TablePackageImpl.init(); - /** - * The number of structural features of the 'Cell Label Widget Description' class. - * + * The number of structural features of the 'Row Context Menu Entry' class. * * @generated * @ordered */ - int CELL_LABEL_WIDGET_DESCRIPTION_FEATURE_COUNT = CELL_WIDGET_DESCRIPTION_FEATURE_COUNT + 1; + int ROW_CONTEXT_MENU_ENTRY_FEATURE_COUNT = 5; /** - * The number of operations of the 'Cell Label Widget Description' class. * * @generated * @ordered */ - int CELL_LABEL_WIDGET_DESCRIPTION_OPERATION_COUNT = CELL_WIDGET_DESCRIPTION_OPERATION_COUNT; + int ROW_CONTEXT_MENU_ENTRY_OPERATION_COUNT = 0; /** * The meta object id for the @@ -651,7 +722,7 @@ public interface TablePackage extends EPackage { * @see org.eclipse.sirius.components.view.table.impl.CellTextareaWidgetDescriptionImpl * @see org.eclipse.sirius.components.view.table.impl.TablePackageImpl#getCellTextareaWidgetDescription() */ - int CELL_TEXTAREA_WIDGET_DESCRIPTION = 8; + int CELL_TEXTAREA_WIDGET_DESCRIPTION = 9; /** * The feature id for the 'Body' containment reference list. + * + * @return the meta object for the containment reference list 'Context Menu Entries'. + * @generated + * @see org.eclipse.sirius.components.view.table.RowDescription#getContextMenuEntries() + * @see #getRowDescription() + */ + EReference getRowDescription_ContextMenuEntries(); + /** * Returns the meta object for class '{@link org.eclipse.sirius.components.view.table.CellDescription Cell * Description}'. @@ -1070,6 +1153,76 @@ public interface TablePackage extends EPackage { */ EReference getCellTextareaWidgetDescription_Body(); + /** + * Returns the meta object for class '{@link org.eclipse.sirius.components.view.table.RowContextMenuEntry Row + * Context Menu Entry}'. + * + * @return the meta object for class 'Row Context Menu Entry'. + * @generated + * @see org.eclipse.sirius.components.view.table.RowContextMenuEntry + */ + EClass getRowContextMenuEntry(); + + /** + * Returns the meta object for the attribute + * '{@link org.eclipse.sirius.components.view.table.RowContextMenuEntry#getName Name}'. + * + * @return the meta object for the attribute 'Name'. + * @generated + * @see org.eclipse.sirius.components.view.table.RowContextMenuEntry#getName() + * @see #getRowContextMenuEntry() + */ + EAttribute getRowContextMenuEntry_Name(); + + /** + * Returns the meta object for the attribute + * '{@link org.eclipse.sirius.components.view.table.RowContextMenuEntry#getLabelExpression Label + * Expression}'. + * + * @return the meta object for the attribute 'Label Expression'. + * @generated + * @see org.eclipse.sirius.components.view.table.RowContextMenuEntry#getLabelExpression() + * @see #getRowContextMenuEntry() + */ + EAttribute getRowContextMenuEntry_LabelExpression(); + + /** + * Returns the meta object for the attribute + * '{@link org.eclipse.sirius.components.view.table.RowContextMenuEntry#getIconURLExpression Icon URL + * Expression}'. + * + * @return the meta object for the attribute 'Icon URL Expression'. + * @generated + * @see org.eclipse.sirius.components.view.table.RowContextMenuEntry#getIconURLExpression() + * @see #getRowContextMenuEntry() + */ + EAttribute getRowContextMenuEntry_IconURLExpression(); + + /** + * Returns the meta object for the attribute + * '{@link org.eclipse.sirius.components.view.table.RowContextMenuEntry#getPreconditionExpression Precondition + * Expression}'. + * + * @return the meta object for the attribute 'Precondition Expression'. + * @generated + * @see org.eclipse.sirius.components.view.table.RowContextMenuEntry#getPreconditionExpression() + * @see #getRowContextMenuEntry() + */ + EAttribute getRowContextMenuEntry_PreconditionExpression(); + + /** + * Returns the meta object for the containment reference list + * '{@link org.eclipse.sirius.components.view.table.RowContextMenuEntry#getBody Body}'. + * + * @return the meta object for the containment reference list 'Body'. + * @generated + * @see org.eclipse.sirius.components.view.table.RowContextMenuEntry#getBody() + * @see #getRowContextMenuEntry() + */ + EReference getRowContextMenuEntry_Body(); + /** * Returns the factory that creates the instances of the model. * @@ -1286,6 +1439,14 @@ interface Literals { */ EAttribute ROW_DESCRIPTION__IS_RESIZABLE_EXPRESSION = eINSTANCE.getRowDescription_IsResizableExpression(); + /** + * The meta object literal for the 'Context Menu Entries' containment reference list feature. + * + * + * @generated + */ + EReference ROW_DESCRIPTION__CONTEXT_MENU_ENTRIES = eINSTANCE.getRowDescription_ContextMenuEntries(); + /** * The meta object literal for the '{@link org.eclipse.sirius.components.view.table.impl.CellDescriptionImpl * Cell Description}' class. @@ -1387,6 +1548,56 @@ interface Literals { */ EReference CELL_TEXTAREA_WIDGET_DESCRIPTION__BODY = eINSTANCE.getCellTextareaWidgetDescription_Body(); + /** + * The meta object literal for the '{@link org.eclipse.sirius.components.view.table.impl.RowContextMenuEntryImpl + * Row Context Menu Entry}' class. + * + * @generated + * @see org.eclipse.sirius.components.view.table.impl.RowContextMenuEntryImpl + * @see org.eclipse.sirius.components.view.table.impl.TablePackageImpl#getRowContextMenuEntry() + */ + EClass ROW_CONTEXT_MENU_ENTRY = eINSTANCE.getRowContextMenuEntry(); + + /** + * The meta object literal for the 'Name' attribute feature. + * + * @generated + */ + EAttribute ROW_CONTEXT_MENU_ENTRY__NAME = eINSTANCE.getRowContextMenuEntry_Name(); + + /** + * The meta object literal for the 'Label Expression' attribute feature. + * + * + * @generated + */ + EAttribute ROW_CONTEXT_MENU_ENTRY__LABEL_EXPRESSION = eINSTANCE.getRowContextMenuEntry_LabelExpression(); + + /** + * The meta object literal for the 'Icon URL Expression' attribute feature. + * + * @generated + */ + EAttribute ROW_CONTEXT_MENU_ENTRY__ICON_URL_EXPRESSION = eINSTANCE.getRowContextMenuEntry_IconURLExpression(); + + /** + * The meta object literal for the 'Precondition Expression' attribute feature. + * + * @generated + */ + EAttribute ROW_CONTEXT_MENU_ENTRY__PRECONDITION_EXPRESSION = eINSTANCE.getRowContextMenuEntry_PreconditionExpression(); + + /** + * The meta object literal for the 'Body' containment reference list feature. + * + * @generated + */ + EReference ROW_CONTEXT_MENU_ENTRY__BODY = eINSTANCE.getRowContextMenuEntry_Body(); + } } // TablePackage diff --git a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/impl/RowContextMenuEntryImpl.java b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/impl/RowContextMenuEntryImpl.java new file mode 100644 index 0000000000..fb7a92cefd --- /dev/null +++ b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/impl/RowContextMenuEntryImpl.java @@ -0,0 +1,395 @@ +/******************************************************************************* + * Copyright (c) 2025 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.view.table.impl; + +import java.util.Collection; +import java.util.Objects; + +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.notify.NotificationChain; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.impl.ENotificationImpl; +import org.eclipse.emf.ecore.impl.MinimalEObjectImpl; +import org.eclipse.emf.ecore.util.EObjectContainmentEList; +import org.eclipse.emf.ecore.util.InternalEList; +import org.eclipse.sirius.components.view.Operation; +import org.eclipse.sirius.components.view.table.RowContextMenuEntry; +import org.eclipse.sirius.components.view.table.TablePackage; + +/** + * An implementation of the model object 'Row Context Menu Entry'. + *

    + * The following features are implemented: + *

    + *
      + *
    • {@link org.eclipse.sirius.components.view.table.impl.RowContextMenuEntryImpl#getName Name}
    • + *
    • {@link org.eclipse.sirius.components.view.table.impl.RowContextMenuEntryImpl#getLabelExpression Label + * Expression}
    • + *
    • {@link org.eclipse.sirius.components.view.table.impl.RowContextMenuEntryImpl#getIconURLExpression Icon URL + * Expression}
    • + *
    • {@link org.eclipse.sirius.components.view.table.impl.RowContextMenuEntryImpl#getPreconditionExpression + * Precondition Expression}
    • + *
    • {@link org.eclipse.sirius.components.view.table.impl.RowContextMenuEntryImpl#getBody Body}
    • + *
    + * + * @generated + */ +public class RowContextMenuEntryImpl extends MinimalEObjectImpl.Container implements RowContextMenuEntry { + + /** + * The default value of the '{@link #getName() Name}' attribute. + * + * @generated + * @ordered + * @see #getName() + */ + protected static final String NAME_EDEFAULT = null; + /** + * The default value of the '{@link #getLabelExpression() Label Expression}' attribute. + * + * @generated + * @ordered + * @see #getLabelExpression() + */ + protected static final String LABEL_EXPRESSION_EDEFAULT = null; + /** + * The default value of the '{@link #getIconURLExpression() Icon URL Expression}' attribute. + * + * @generated + * @ordered + * @see #getIconURLExpression() + */ + protected static final String ICON_URL_EXPRESSION_EDEFAULT = null; + /** + * The default value of the '{@link #getPreconditionExpression() Precondition Expression}' attribute. + * + * @generated + * @ordered + * @see #getPreconditionExpression() + */ + protected static final String PRECONDITION_EXPRESSION_EDEFAULT = null; + /** + * The cached value of the '{@link #getName() Name}' attribute. + * + * @generated + * @ordered + * @see #getName() + */ + protected String name = NAME_EDEFAULT; + /** + * The cached value of the '{@link #getLabelExpression() Label Expression}' attribute. + * + * @generated + * @ordered + * @see #getLabelExpression() + */ + protected String labelExpression = LABEL_EXPRESSION_EDEFAULT; + /** + * The cached value of the '{@link #getIconURLExpression() Icon URL Expression}' attribute. + * + * @generated + * @ordered + * @see #getIconURLExpression() + */ + protected String iconURLExpression = ICON_URL_EXPRESSION_EDEFAULT; + /** + * The cached value of the '{@link #getPreconditionExpression() Precondition Expression}' attribute. + * + * @generated + * @ordered + * @see #getPreconditionExpression() + */ + protected String preconditionExpression = PRECONDITION_EXPRESSION_EDEFAULT; + + /** + * The cached value of the '{@link #getBody() Body}' containment reference list. + * + * + * @generated + * @ordered + * @see #getBody() + */ + protected EList body; + + /** + * + * + * @generated + */ + protected RowContextMenuEntryImpl() { + super(); + } + + /** + * + * + * @generated + */ + @Override + protected EClass eStaticClass() { + return TablePackage.Literals.ROW_CONTEXT_MENU_ENTRY; + } + + /** + * + * + * @generated + */ + @Override + public String getName() { + return this.name; + } + + /** + * + * + * @generated + */ + @Override + public void setName(String newName) { + String oldName = this.name; + this.name = newName; + if (this.eNotificationRequired()) + this.eNotify(new ENotificationImpl(this, Notification.SET, TablePackage.ROW_CONTEXT_MENU_ENTRY__NAME, oldName, this.name)); + } + + /** + * + * + * @generated + */ + @Override + public String getLabelExpression() { + return this.labelExpression; + } + + /** + * + * + * @generated + */ + @Override + public void setLabelExpression(String newLabelExpression) { + String oldLabelExpression = this.labelExpression; + this.labelExpression = newLabelExpression; + if (this.eNotificationRequired()) + this.eNotify(new ENotificationImpl(this, Notification.SET, TablePackage.ROW_CONTEXT_MENU_ENTRY__LABEL_EXPRESSION, oldLabelExpression, this.labelExpression)); + } + + /** + * + * + * @generated + */ + @Override + public String getIconURLExpression() { + return this.iconURLExpression; + } + + /** + * + * + * @generated + */ + @Override + public void setIconURLExpression(String newIconURLExpression) { + String oldIconURLExpression = this.iconURLExpression; + this.iconURLExpression = newIconURLExpression; + if (this.eNotificationRequired()) + this.eNotify(new ENotificationImpl(this, Notification.SET, TablePackage.ROW_CONTEXT_MENU_ENTRY__ICON_URL_EXPRESSION, oldIconURLExpression, this.iconURLExpression)); + } + + /** + * + * + * @generated + */ + @Override + public String getPreconditionExpression() { + return this.preconditionExpression; + } + + /** + * + * + * @generated + */ + @Override + public void setPreconditionExpression(String newPreconditionExpression) { + String oldPreconditionExpression = this.preconditionExpression; + this.preconditionExpression = newPreconditionExpression; + if (this.eNotificationRequired()) + this.eNotify(new ENotificationImpl(this, Notification.SET, TablePackage.ROW_CONTEXT_MENU_ENTRY__PRECONDITION_EXPRESSION, oldPreconditionExpression, this.preconditionExpression)); + } + + /** + * + * + * @generated + */ + @Override + public EList getBody() { + if (this.body == null) { + this.body = new EObjectContainmentEList<>(Operation.class, this, TablePackage.ROW_CONTEXT_MENU_ENTRY__BODY); + } + return this.body; + } + + /** + * + * + * @generated + */ + @Override + public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) { + switch (featureID) { + case TablePackage.ROW_CONTEXT_MENU_ENTRY__BODY: + return ((InternalEList) this.getBody()).basicRemove(otherEnd, msgs); + } + return super.eInverseRemove(otherEnd, featureID, msgs); + } + + /** + * + * + * @generated + */ + @Override + public Object eGet(int featureID, boolean resolve, boolean coreType) { + switch (featureID) { + case TablePackage.ROW_CONTEXT_MENU_ENTRY__NAME: + return this.getName(); + case TablePackage.ROW_CONTEXT_MENU_ENTRY__LABEL_EXPRESSION: + return this.getLabelExpression(); + case TablePackage.ROW_CONTEXT_MENU_ENTRY__ICON_URL_EXPRESSION: + return this.getIconURLExpression(); + case TablePackage.ROW_CONTEXT_MENU_ENTRY__PRECONDITION_EXPRESSION: + return this.getPreconditionExpression(); + case TablePackage.ROW_CONTEXT_MENU_ENTRY__BODY: + return this.getBody(); + } + return super.eGet(featureID, resolve, coreType); + } + + /** + * + * + * @generated + */ + @SuppressWarnings("unchecked") + @Override + public void eSet(int featureID, Object newValue) { + switch (featureID) { + case TablePackage.ROW_CONTEXT_MENU_ENTRY__NAME: + this.setName((String) newValue); + return; + case TablePackage.ROW_CONTEXT_MENU_ENTRY__LABEL_EXPRESSION: + this.setLabelExpression((String) newValue); + return; + case TablePackage.ROW_CONTEXT_MENU_ENTRY__ICON_URL_EXPRESSION: + this.setIconURLExpression((String) newValue); + return; + case TablePackage.ROW_CONTEXT_MENU_ENTRY__PRECONDITION_EXPRESSION: + this.setPreconditionExpression((String) newValue); + return; + case TablePackage.ROW_CONTEXT_MENU_ENTRY__BODY: + this.getBody().clear(); + this.getBody().addAll((Collection) newValue); + return; + } + super.eSet(featureID, newValue); + } + + /** + * + * + * @generated + */ + @Override + public void eUnset(int featureID) { + switch (featureID) { + case TablePackage.ROW_CONTEXT_MENU_ENTRY__NAME: + this.setName(NAME_EDEFAULT); + return; + case TablePackage.ROW_CONTEXT_MENU_ENTRY__LABEL_EXPRESSION: + this.setLabelExpression(LABEL_EXPRESSION_EDEFAULT); + return; + case TablePackage.ROW_CONTEXT_MENU_ENTRY__ICON_URL_EXPRESSION: + this.setIconURLExpression(ICON_URL_EXPRESSION_EDEFAULT); + return; + case TablePackage.ROW_CONTEXT_MENU_ENTRY__PRECONDITION_EXPRESSION: + this.setPreconditionExpression(PRECONDITION_EXPRESSION_EDEFAULT); + return; + case TablePackage.ROW_CONTEXT_MENU_ENTRY__BODY: + this.getBody().clear(); + return; + } + super.eUnset(featureID); + } + + /** + * + * + * @generated + */ + @Override + public boolean eIsSet(int featureID) { + switch (featureID) { + case TablePackage.ROW_CONTEXT_MENU_ENTRY__NAME: + return !Objects.equals(NAME_EDEFAULT, this.name); + case TablePackage.ROW_CONTEXT_MENU_ENTRY__LABEL_EXPRESSION: + return !Objects.equals(LABEL_EXPRESSION_EDEFAULT, this.labelExpression); + case TablePackage.ROW_CONTEXT_MENU_ENTRY__ICON_URL_EXPRESSION: + return !Objects.equals(ICON_URL_EXPRESSION_EDEFAULT, this.iconURLExpression); + case TablePackage.ROW_CONTEXT_MENU_ENTRY__PRECONDITION_EXPRESSION: + return !Objects.equals(PRECONDITION_EXPRESSION_EDEFAULT, this.preconditionExpression); + case TablePackage.ROW_CONTEXT_MENU_ENTRY__BODY: + return this.body != null && !this.body.isEmpty(); + } + return super.eIsSet(featureID); + } + + /** + * + * + * @generated + */ + @Override + public String toString() { + if (this.eIsProxy()) + return super.toString(); + + String result = super.toString() + " (name: " + + this.name + + ", labelExpression: " + + this.labelExpression + + ", iconURLExpression: " + + this.iconURLExpression + + ", preconditionExpression: " + + this.preconditionExpression + + ')'; + return result; + } + +} // RowContextMenuEntryImpl diff --git a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/impl/RowDescriptionImpl.java b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/impl/RowDescriptionImpl.java index 49a63e2a59..cd64a76e32 100644 --- a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/impl/RowDescriptionImpl.java +++ b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/impl/RowDescriptionImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024 CEA LIST. + * Copyright (c) 2024, 2025 CEA LIST. * 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 @@ -12,11 +12,18 @@ *******************************************************************************/ package org.eclipse.sirius.components.view.table.impl; +import java.util.Collection; import java.util.Objects; import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.notify.NotificationChain; +import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.impl.ENotificationImpl; +import org.eclipse.emf.ecore.util.EObjectContainmentEList; +import org.eclipse.emf.ecore.util.InternalEList; +import org.eclipse.sirius.components.view.table.RowContextMenuEntry; import org.eclipse.sirius.components.view.table.RowDescription; import org.eclipse.sirius.components.view.table.TablePackage; @@ -128,6 +135,16 @@ public class RowDescriptionImpl extends TableElementDescriptionImpl implements R */ protected String isResizableExpression = IS_RESIZABLE_EXPRESSION_EDEFAULT; + /** + * The cached value of the '{@link #getContextMenuEntries() Context Menu Entries}' containment reference + * list. + * + * @generated + * @ordered + * @see #getContextMenuEntries() + */ + protected EList contextMenuEntries; + /** * * @@ -262,6 +279,33 @@ public void setIsResizableExpression(String newIsResizableExpression) { this.eNotify(new ENotificationImpl(this, Notification.SET, TablePackage.ROW_DESCRIPTION__IS_RESIZABLE_EXPRESSION, oldIsResizableExpression, this.isResizableExpression)); } + /** + * + * + * @generated + */ + @Override + public EList getContextMenuEntries() { + if (this.contextMenuEntries == null) { + this.contextMenuEntries = new EObjectContainmentEList<>(RowContextMenuEntry.class, this, TablePackage.ROW_DESCRIPTION__CONTEXT_MENU_ENTRIES); + } + return this.contextMenuEntries; + } + + /** + * + * + * @generated + */ + @Override + public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) { + switch (featureID) { + case TablePackage.ROW_DESCRIPTION__CONTEXT_MENU_ENTRIES: + return ((InternalEList) this.getContextMenuEntries()).basicRemove(otherEnd, msgs); + } + return super.eInverseRemove(otherEnd, featureID, msgs); + } + /** * * @@ -280,6 +324,8 @@ public Object eGet(int featureID, boolean resolve, boolean coreType) { return this.getInitialHeightExpression(); case TablePackage.ROW_DESCRIPTION__IS_RESIZABLE_EXPRESSION: return this.getIsResizableExpression(); + case TablePackage.ROW_DESCRIPTION__CONTEXT_MENU_ENTRIES: + return this.getContextMenuEntries(); } return super.eGet(featureID, resolve, coreType); } @@ -289,6 +335,7 @@ public Object eGet(int featureID, boolean resolve, boolean coreType) { * * @generated */ + @SuppressWarnings("unchecked") @Override public void eSet(int featureID, Object newValue) { switch (featureID) { @@ -307,6 +354,10 @@ public void eSet(int featureID, Object newValue) { case TablePackage.ROW_DESCRIPTION__IS_RESIZABLE_EXPRESSION: this.setIsResizableExpression((String) newValue); return; + case TablePackage.ROW_DESCRIPTION__CONTEXT_MENU_ENTRIES: + this.getContextMenuEntries().clear(); + this.getContextMenuEntries().addAll((Collection) newValue); + return; } super.eSet(featureID, newValue); } @@ -334,6 +385,9 @@ public void eUnset(int featureID) { case TablePackage.ROW_DESCRIPTION__IS_RESIZABLE_EXPRESSION: this.setIsResizableExpression(IS_RESIZABLE_EXPRESSION_EDEFAULT); return; + case TablePackage.ROW_DESCRIPTION__CONTEXT_MENU_ENTRIES: + this.getContextMenuEntries().clear(); + return; } super.eUnset(featureID); } @@ -356,6 +410,8 @@ public boolean eIsSet(int featureID) { return INITIAL_HEIGHT_EXPRESSION_EDEFAULT == null ? this.initialHeightExpression != null : !INITIAL_HEIGHT_EXPRESSION_EDEFAULT.equals(this.initialHeightExpression); case TablePackage.ROW_DESCRIPTION__IS_RESIZABLE_EXPRESSION: return IS_RESIZABLE_EXPRESSION_EDEFAULT == null ? this.isResizableExpression != null : !IS_RESIZABLE_EXPRESSION_EDEFAULT.equals(this.isResizableExpression); + case TablePackage.ROW_DESCRIPTION__CONTEXT_MENU_ENTRIES: + return this.contextMenuEntries != null && !this.contextMenuEntries.isEmpty(); } return super.eIsSet(featureID); } diff --git a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/impl/TableFactoryImpl.java b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/impl/TableFactoryImpl.java index f0fef5c64d..864511a026 100644 --- a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/impl/TableFactoryImpl.java +++ b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/impl/TableFactoryImpl.java @@ -22,6 +22,7 @@ import org.eclipse.sirius.components.view.table.CellTextareaWidgetDescription; import org.eclipse.sirius.components.view.table.CellTextfieldWidgetDescription; import org.eclipse.sirius.components.view.table.ColumnDescription; +import org.eclipse.sirius.components.view.table.RowContextMenuEntry; import org.eclipse.sirius.components.view.table.RowDescription; import org.eclipse.sirius.components.view.table.TableDescription; import org.eclipse.sirius.components.view.table.TableFactory; @@ -82,6 +83,8 @@ public EObject create(EClass eClass) { return this.createCellLabelWidgetDescription(); case TablePackage.CELL_TEXTAREA_WIDGET_DESCRIPTION: return this.createCellTextareaWidgetDescription(); + case TablePackage.ROW_CONTEXT_MENU_ENTRY: + return this.createRowContextMenuEntry(); default: throw new IllegalArgumentException("The class '" + eClass.getName() + "' is not a valid classifier"); } @@ -164,6 +167,17 @@ public CellTextareaWidgetDescription createCellTextareaWidgetDescription() { return cellTextareaWidgetDescription; } + /** + * + * + * @generated + */ + @Override + public RowContextMenuEntry createRowContextMenuEntry() { + RowContextMenuEntryImpl rowContextMenuEntry = new RowContextMenuEntryImpl(); + return rowContextMenuEntry; + } + /** * * @@ -184,5 +198,5 @@ public TablePackage getTablePackage() { public static TablePackage getPackage() { return TablePackage.eINSTANCE; } - + } // TableFactoryImpl diff --git a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/impl/TablePackageImpl.java b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/impl/TablePackageImpl.java index 18ff9b0401..1e359ec63b 100644 --- a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/impl/TablePackageImpl.java +++ b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/impl/TablePackageImpl.java @@ -24,6 +24,7 @@ import org.eclipse.sirius.components.view.table.CellTextfieldWidgetDescription; import org.eclipse.sirius.components.view.table.CellWidgetDescription; import org.eclipse.sirius.components.view.table.ColumnDescription; +import org.eclipse.sirius.components.view.table.RowContextMenuEntry; import org.eclipse.sirius.components.view.table.RowDescription; import org.eclipse.sirius.components.view.table.TableDescription; import org.eclipse.sirius.components.view.table.TableElementDescription; @@ -100,13 +101,20 @@ public class TablePackageImpl extends EPackageImpl implements TablePackage { */ private EClass cellTextareaWidgetDescriptionEClass = null; + /** + * + * + * @generated + */ + private EClass rowContextMenuEntryEClass = null; + /** * * * @generated */ private static boolean isInited = false; - + /** * * @@ -408,6 +416,16 @@ public EAttribute getRowDescription_IsResizableExpression() { return (EAttribute) this.rowDescriptionEClass.getEStructuralFeatures().get(4); } + /** + * + * + * @generated + */ + @Override + public EReference getRowDescription_ContextMenuEntries() { + return (EReference) this.rowDescriptionEClass.getEStructuralFeatures().get(5); + } + /** * * @@ -518,6 +536,66 @@ public EReference getCellTextareaWidgetDescription_Body() { return (EReference) this.cellTextareaWidgetDescriptionEClass.getEStructuralFeatures().get(0); } + /** + * + * + * @generated + */ + @Override + public EClass getRowContextMenuEntry() { + return this.rowContextMenuEntryEClass; + } + + /** + * + * + * @generated + */ + @Override + public EAttribute getRowContextMenuEntry_Name() { + return (EAttribute) this.rowContextMenuEntryEClass.getEStructuralFeatures().get(0); + } + + /** + * + * + * @generated + */ + @Override + public EAttribute getRowContextMenuEntry_LabelExpression() { + return (EAttribute) this.rowContextMenuEntryEClass.getEStructuralFeatures().get(1); + } + + /** + * + * + * @generated + */ + @Override + public EAttribute getRowContextMenuEntry_IconURLExpression() { + return (EAttribute) this.rowContextMenuEntryEClass.getEStructuralFeatures().get(2); + } + + /** + * + * + * @generated + */ + @Override + public EAttribute getRowContextMenuEntry_PreconditionExpression() { + return (EAttribute) this.rowContextMenuEntryEClass.getEStructuralFeatures().get(3); + } + + /** + * + * + * @generated + */ + @Override + public EReference getRowContextMenuEntry_Body() { + return (EReference) this.rowContextMenuEntryEClass.getEStructuralFeatures().get(4); + } + /** * * @@ -566,6 +644,7 @@ public void createPackageContents() { this.createEAttribute(this.rowDescriptionEClass, ROW_DESCRIPTION__HEADER_INDEX_LABEL_EXPRESSION); this.createEAttribute(this.rowDescriptionEClass, ROW_DESCRIPTION__INITIAL_HEIGHT_EXPRESSION); this.createEAttribute(this.rowDescriptionEClass, ROW_DESCRIPTION__IS_RESIZABLE_EXPRESSION); + this.createEReference(this.rowDescriptionEClass, ROW_DESCRIPTION__CONTEXT_MENU_ENTRIES); this.cellDescriptionEClass = this.createEClass(CELL_DESCRIPTION); this.createEAttribute(this.cellDescriptionEClass, CELL_DESCRIPTION__VALUE_EXPRESSION); @@ -582,6 +661,13 @@ public void createPackageContents() { this.cellTextareaWidgetDescriptionEClass = this.createEClass(CELL_TEXTAREA_WIDGET_DESCRIPTION); this.createEReference(this.cellTextareaWidgetDescriptionEClass, CELL_TEXTAREA_WIDGET_DESCRIPTION__BODY); + + this.rowContextMenuEntryEClass = this.createEClass(ROW_CONTEXT_MENU_ENTRY); + this.createEAttribute(this.rowContextMenuEntryEClass, ROW_CONTEXT_MENU_ENTRY__NAME); + this.createEAttribute(this.rowContextMenuEntryEClass, ROW_CONTEXT_MENU_ENTRY__LABEL_EXPRESSION); + this.createEAttribute(this.rowContextMenuEntryEClass, ROW_CONTEXT_MENU_ENTRY__ICON_URL_EXPRESSION); + this.createEAttribute(this.rowContextMenuEntryEClass, ROW_CONTEXT_MENU_ENTRY__PRECONDITION_EXPRESSION); + this.createEReference(this.rowContextMenuEntryEClass, ROW_CONTEXT_MENU_ENTRY__BODY); } /** @@ -665,6 +751,8 @@ public void initializePackageContents() { !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); this.initEAttribute(this.getRowDescription_IsResizableExpression(), theViewPackage.getInterpretedExpression(), "isResizableExpression", "", 0, 1, RowDescription.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); + this.initEReference(this.getRowDescription_ContextMenuEntries(), this.getRowContextMenuEntry(), null, "contextMenuEntries", null, 0, -1, RowDescription.class, !IS_TRANSIENT, !IS_VOLATILE, + IS_CHANGEABLE, IS_COMPOSITE, !IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); this.initEClass(this.cellDescriptionEClass, CellDescription.class, "CellDescription", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); this.initEAttribute(this.getCellDescription_ValueExpression(), theViewPackage.getInterpretedExpression(), "valueExpression", "", 0, 1, CellDescription.class, !IS_TRANSIENT, !IS_VOLATILE, @@ -684,6 +772,18 @@ public void initializePackageContents() { this.initEAttribute(this.getCellLabelWidgetDescription_IconExpression(), theViewPackage.getInterpretedExpression(), "iconExpression", "", 0, 1, CellLabelWidgetDescription.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); + this.initEClass(this.rowContextMenuEntryEClass, RowContextMenuEntry.class, "RowContextMenuEntry", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); + this.initEAttribute(this.getRowContextMenuEntry_Name(), theViewPackage.getIdentifier(), "name", null, 1, 1, RowContextMenuEntry.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, + !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); + this.initEAttribute(this.getRowContextMenuEntry_LabelExpression(), theViewPackage.getInterpretedExpression(), "labelExpression", null, 0, 1, RowContextMenuEntry.class, !IS_TRANSIENT, + !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); + this.initEAttribute(this.getRowContextMenuEntry_IconURLExpression(), theViewPackage.getInterpretedExpression(), "iconURLExpression", null, 0, 1, RowContextMenuEntry.class, !IS_TRANSIENT, + !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); + this.initEAttribute(this.getRowContextMenuEntry_PreconditionExpression(), theViewPackage.getInterpretedExpression(), "preconditionExpression", null, 0, 1, RowContextMenuEntry.class, + !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); + this.initEReference(this.getRowContextMenuEntry_Body(), theViewPackage.getOperation(), null, "body", null, 0, -1, RowContextMenuEntry.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, + IS_COMPOSITE, !IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); + this.initEClass(this.cellTextareaWidgetDescriptionEClass, CellTextareaWidgetDescription.class, "CellTextareaWidgetDescription", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); this.initEReference(this.getCellTextareaWidgetDescription_Body(), theViewPackage.getOperation(), null, "body", null, 0, -1, CellTextareaWidgetDescription.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_COMPOSITE, !IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); diff --git a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/util/TableAdapterFactory.java b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/util/TableAdapterFactory.java index 6dd1e55d9d..c44fd490d1 100644 --- a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/util/TableAdapterFactory.java +++ b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/util/TableAdapterFactory.java @@ -23,6 +23,7 @@ import org.eclipse.sirius.components.view.table.CellTextfieldWidgetDescription; import org.eclipse.sirius.components.view.table.CellWidgetDescription; import org.eclipse.sirius.components.view.table.ColumnDescription; +import org.eclipse.sirius.components.view.table.RowContextMenuEntry; import org.eclipse.sirius.components.view.table.RowDescription; import org.eclipse.sirius.components.view.table.TableDescription; import org.eclipse.sirius.components.view.table.TableElementDescription; @@ -95,6 +96,11 @@ public Adapter caseCellTextareaWidgetDescription(CellTextareaWidgetDescription o return TableAdapterFactory.this.createCellTextareaWidgetDescriptionAdapter(); } + @Override + public Adapter caseRowContextMenuEntry(RowContextMenuEntry object) { + return TableAdapterFactory.this.createRowContextMenuEntryAdapter(); + } + @Override public Adapter caseRepresentationDescription(RepresentationDescription object) { return TableAdapterFactory.this.createRepresentationDescriptionAdapter(); @@ -275,6 +281,20 @@ public Adapter createCellTextareaWidgetDescriptionAdapter() { return null; } + /** + * Creates a new adapter for an object of class '{@link org.eclipse.sirius.components.view.table.RowContextMenuEntry + * Row Context Menu Entry}'. This default implementation returns null so that we + * can easily ignore cases; it's useful to ignore a case when inheritance will catch all the cases anyway. + * + * @return the new adapter. + * @see org.eclipse.sirius.components.view.table.RowContextMenuEntry + * @generated + */ + public Adapter createRowContextMenuEntryAdapter() { + return null; + } + /** * Creates a new adapter for an object of class '{@link org.eclipse.sirius.components.view.RepresentationDescription * Representation Description}'. This default implementation returns null so that diff --git a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/util/TableSwitch.java b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/util/TableSwitch.java index 70f46a87ca..596fed30d4 100644 --- a/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/util/TableSwitch.java +++ b/packages/view/backend/sirius-components-view-table/src/main/java/org/eclipse/sirius/components/view/table/util/TableSwitch.java @@ -22,6 +22,7 @@ import org.eclipse.sirius.components.view.table.CellTextfieldWidgetDescription; import org.eclipse.sirius.components.view.table.CellWidgetDescription; import org.eclipse.sirius.components.view.table.ColumnDescription; +import org.eclipse.sirius.components.view.table.RowContextMenuEntry; import org.eclipse.sirius.components.view.table.RowDescription; import org.eclipse.sirius.components.view.table.TableDescription; import org.eclipse.sirius.components.view.table.TableElementDescription; @@ -156,6 +157,13 @@ protected T doSwitch(int classifierID, EObject theEObject) { result = this.defaultCase(theEObject); return result; } + case TablePackage.ROW_CONTEXT_MENU_ENTRY: { + RowContextMenuEntry rowContextMenuEntry = (RowContextMenuEntry) theEObject; + T result = this.caseRowContextMenuEntry(rowContextMenuEntry); + if (result == null) + result = this.defaultCase(theEObject); + return result; + } default: return this.defaultCase(theEObject); } @@ -295,6 +303,21 @@ public T caseCellTextareaWidgetDescription(CellTextareaWidgetDescription object) return null; } + /** + * Returns the result of interpreting the object as an instance of 'Row Context Menu Entry'. This implementation returns null; returning a non-null result will terminate the switch. + * + * @param object + * the target of the switch. + * @return the result of interpreting the object as an instance of 'Row Context Menu Entry'. + * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject) + * @generated + */ + public T caseRowContextMenuEntry(RowContextMenuEntry object) { + return null; + } + /** * Returns the result of interpreting the object as an instance of 'Representation Description'. This implementation returns null; returning a non-null result will terminate the switch.