Skip to content

Commit

Permalink
[1914] Add support for custom widgets
Browse files Browse the repository at this point in the history
Bug: #1914
Signed-off-by: Pierre-Charles David <pierre-charles.david@obeo.fr>
  • Loading branch information
pcdavid authored and sbegaudeau committed May 25, 2023
1 parent 6926198 commit 92b4de2
Show file tree
Hide file tree
Showing 74 changed files with 979 additions and 269 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.adoc
Expand Up @@ -69,6 +69,8 @@ All visible tree items containing the value typed in the filter bar will be high
The filter button inside the filter bar allows to filter (hide) all visible tree items not containing the value typed in the filter bar.
+
image:doc/screenshots/filterBarFilterButton.png[Filter Bar Filter Button,30%,30%]
- https://github.com/eclipse-sirius/sirius-components/issues/1914[#1914] [form] It is now possible for applications to provide their own custom widgets without forking Sirius Components.
See link:how-to/contribute-custom-widget.adoc[the documentation] for more details.

- https://github.com/eclipse-sirius/sirius-components/issues/1830[#1830] [layout] This feature is experimental and can be activated on a diagram by adding "__EXPERIMENTAL" to its name. The new algorithm does the minimum possible to place node without overlap.
- https://github.com/eclipse-sirius/sirius-components/issues/1985[|#1985] [sirius-web] It is now possible to use in-memory View-based representations by registering them in the new `InMemoryViewRegistry`.
Expand Down
Expand Up @@ -237,8 +237,8 @@ private void checkResult(FormDescription description) {
VariableManager variableManager = new VariableManager();
variableManager.put(VariableManager.SELF, List.of(EcorePackage.eINSTANCE));

FormRenderer formRenderer = new FormRenderer();
FormComponentProps props = new FormComponentProps(variableManager, description);
FormRenderer formRenderer = new FormRenderer(List.of());
FormComponentProps props = new FormComponentProps(variableManager, description, List.of());
Element element = new Element(FormComponent.class, props);
Form form = formRenderer.render(element);

Expand Down
@@ -0,0 +1,60 @@
/*******************************************************************************
* Copyright (c) 2023 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.collaborative.api;

import java.util.Objects;

import org.eclipse.sirius.components.core.api.IRepresentationDescriptionSearchService;
import org.springframework.stereotype.Service;

/**
* Bundles the common dependencies that most {@link IRepresentationEventProcessorFactory} implementations need into a
* single object for convenience.
*
* @author pcdavid
*/
@Service
public class RepresentationEventProcessorFactoryConfiguration {

private final IRepresentationDescriptionSearchService representationDescriptionSearchService;

private final IRepresentationSearchService representationSearchService;

private final IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry;

private final ISubscriptionManagerFactory subscriptionManagerFactory;

public RepresentationEventProcessorFactoryConfiguration(IRepresentationDescriptionSearchService representationDescriptionSearchService, IRepresentationSearchService representationSearchService,
IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry, ISubscriptionManagerFactory subscriptionManagerFactory) {
this.representationDescriptionSearchService = Objects.requireNonNull(representationDescriptionSearchService);
this.representationSearchService = Objects.requireNonNull(representationSearchService);
this.representationRefreshPolicyRegistry = Objects.requireNonNull(representationRefreshPolicyRegistry);
this.subscriptionManagerFactory = Objects.requireNonNull(subscriptionManagerFactory);
}

public IRepresentationDescriptionSearchService getRepresentationDescriptionSearchService() {
return this.representationDescriptionSearchService;
}

public IRepresentationSearchService getRepresentationSearchService() {
return this.representationSearchService;
}

public IRepresentationRefreshPolicyRegistry getRepresentationRefreshPolicyRegistry() {
return this.representationRefreshPolicyRegistry;
}

public ISubscriptionManagerFactory getSubscriptionManagerFactory() {
return this.subscriptionManagerFactory;
}
}
Expand Up @@ -23,6 +23,7 @@
import org.eclipse.sirius.components.collaborative.api.IRepresentationRefreshPolicyRegistry;
import org.eclipse.sirius.components.collaborative.api.IRepresentationSearchService;
import org.eclipse.sirius.components.collaborative.api.ISubscriptionManagerFactory;
import org.eclipse.sirius.components.collaborative.api.RepresentationEventProcessorFactoryConfiguration;
import org.eclipse.sirius.components.collaborative.diagrams.api.DiagramConfiguration;
import org.eclipse.sirius.components.collaborative.diagrams.api.IDiagramCreationService;
import org.eclipse.sirius.components.collaborative.diagrams.api.IDiagramEventHandler;
Expand Down Expand Up @@ -54,16 +55,15 @@ public class DiagramEventProcessorFactory implements IRepresentationEventProcess

private final IRepresentationPersistenceService representationPersistenceService;

public DiagramEventProcessorFactory(IRepresentationSearchService representationSearchService, IDiagramCreationService diagramCreationService, List<IDiagramEventHandler> diagramEventHandlers,
ISubscriptionManagerFactory subscriptionManagerFactory, IRepresentationDescriptionSearchService representationDescriptionSearchService,
IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry, IRepresentationPersistenceService representationPersistenceService) {
this.representationSearchService = Objects.requireNonNull(representationSearchService);
public DiagramEventProcessorFactory(RepresentationEventProcessorFactoryConfiguration configuration, IDiagramCreationService diagramCreationService,
List<IDiagramEventHandler> diagramEventHandlers, IRepresentationPersistenceService representationPersistenceService) {
this.representationSearchService = Objects.requireNonNull(configuration.getRepresentationSearchService());
this.diagramCreationService = Objects.requireNonNull(diagramCreationService);
this.diagramEventHandlers = Objects.requireNonNull(diagramEventHandlers);
this.subscriptionManagerFactory = Objects.requireNonNull(subscriptionManagerFactory);
this.representationDescriptionSearchService = Objects.requireNonNull(representationDescriptionSearchService);
this.representationRefreshPolicyRegistry = Objects.requireNonNull(representationRefreshPolicyRegistry);
this.representationPersistenceService = Objects.requireNonNull(representationPersistenceService);
this.subscriptionManagerFactory = Objects.requireNonNull(configuration.getSubscriptionManagerFactory());
this.representationDescriptionSearchService = Objects.requireNonNull(configuration.getRepresentationDescriptionSearchService());
this.representationRefreshPolicyRegistry = Objects.requireNonNull(configuration.getRepresentationRefreshPolicyRegistry());
}

@Override
Expand Down
Expand Up @@ -27,10 +27,12 @@
import org.eclipse.sirius.components.core.api.IObjectService;
import org.eclipse.sirius.components.core.api.IRepresentationDescriptionSearchService;
import org.eclipse.sirius.components.formdescriptioneditors.FormDescriptionEditor;
import org.eclipse.sirius.components.formdescriptioneditors.IWidgetPreviewConverterProvider;
import org.eclipse.sirius.components.formdescriptioneditors.components.FormDescriptionEditorComponent;
import org.eclipse.sirius.components.formdescriptioneditors.components.FormDescriptionEditorComponentProps;
import org.eclipse.sirius.components.formdescriptioneditors.description.FormDescriptionEditorDescription;
import org.eclipse.sirius.components.formdescriptioneditors.renderer.FormDescriptionEditorRenderer;
import org.eclipse.sirius.components.forms.renderer.IWidgetDescriptor;
import org.eclipse.sirius.components.representations.Element;
import org.eclipse.sirius.components.representations.VariableManager;
import org.springframework.stereotype.Service;
Expand All @@ -52,13 +54,19 @@ public class FormDescriptionEditorCreationService implements IFormDescriptionEdi

private final IObjectService objectService;

private final List<IWidgetDescriptor> widgetDescriptors;

private final List<IWidgetPreviewConverterProvider> customWidgetConverterProviders;

private final Timer timer;

public FormDescriptionEditorCreationService(IRepresentationDescriptionSearchService representationDescriptionSearchService, IRepresentationPersistenceService representationPersistenceService,
IObjectService objectService, MeterRegistry meterRegistry) {
IObjectService objectService, List<IWidgetDescriptor> widgetDescriptors, List<IWidgetPreviewConverterProvider> customWidgetConverterProviders, MeterRegistry meterRegistry) {
this.representationDescriptionSearchService = Objects.requireNonNull(representationDescriptionSearchService);
this.representationPersistenceService = Objects.requireNonNull(representationPersistenceService);
this.objectService = Objects.requireNonNull(objectService);
this.widgetDescriptors = Objects.requireNonNull(widgetDescriptors);
this.customWidgetConverterProviders = Objects.requireNonNull(customWidgetConverterProviders);

this.timer = Timer.builder(Monitoring.REPRESENTATION_EVENT_PROCESSOR_REFRESH)
.tag(Monitoring.NAME, "formdescriptioneditor")
Expand Down Expand Up @@ -109,10 +117,10 @@ private FormDescriptionEditor doRender(String label, Object targetObject, IEditi

Optional<FormDescriptionEditor> optionalPreviousFormDescriptionEditor = optionalFormDescriptionEditorContext.map(IFormDescriptionEditorContext::getFormDescriptionEditor);

var formDescriptionEditorComponentProps = new FormDescriptionEditorComponentProps(variableManager, formDescriptionEditorDescription, optionalPreviousFormDescriptionEditor);
var formDescriptionEditorComponentProps = new FormDescriptionEditorComponentProps(variableManager, formDescriptionEditorDescription, optionalPreviousFormDescriptionEditor, this.widgetDescriptors, this.customWidgetConverterProviders);
Element element = new Element(FormDescriptionEditorComponent.class, formDescriptionEditorComponentProps);

FormDescriptionEditor newFormDescriptionEditor = new FormDescriptionEditorRenderer().render(element);
FormDescriptionEditor newFormDescriptionEditor = new FormDescriptionEditorRenderer(this.widgetDescriptors).render(element);

long end = System.currentTimeMillis();
this.timer.record(end - start, TimeUnit.MILLISECONDS);
Expand Down
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2022 Obeo.
* Copyright (c) 2022, 2023 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
Expand All @@ -22,6 +22,7 @@
import org.eclipse.sirius.components.collaborative.api.IRepresentationRefreshPolicyRegistry;
import org.eclipse.sirius.components.collaborative.api.IRepresentationSearchService;
import org.eclipse.sirius.components.collaborative.api.ISubscriptionManagerFactory;
import org.eclipse.sirius.components.collaborative.api.RepresentationEventProcessorFactoryConfiguration;
import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.FormDescriptionEditorConfiguration;
import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorCreationService;
import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorEventHandler;
Expand Down Expand Up @@ -51,16 +52,14 @@ public class FormDescriptionEditorEventProcessorFactory implements IRepresentati

private final IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry;

public FormDescriptionEditorEventProcessorFactory(IRepresentationDescriptionSearchService representationDescriptionSearchService,
IFormDescriptionEditorCreationService formDescriptionEditormCreationService, IRepresentationSearchService representationSearchService,
List<IFormDescriptionEditorEventHandler> formDescriptionEditorEventHandlers, ISubscriptionManagerFactory subscriptionManagerFactory,
IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry) {
this.representationDescriptionSearchService = Objects.requireNonNull(representationDescriptionSearchService);
public FormDescriptionEditorEventProcessorFactory(RepresentationEventProcessorFactoryConfiguration configuration, IFormDescriptionEditorCreationService formDescriptionEditormCreationService,
List<IFormDescriptionEditorEventHandler> formDescriptionEditorEventHandlers) {
this.representationDescriptionSearchService = Objects.requireNonNull(configuration.getRepresentationDescriptionSearchService());
this.formDescriptionEditormCreationService = Objects.requireNonNull(formDescriptionEditormCreationService);
this.representationSearchService = Objects.requireNonNull(representationSearchService);
this.representationSearchService = Objects.requireNonNull(configuration.getRepresentationSearchService());
this.formDescriptionEditorEventHandlers = Objects.requireNonNull(formDescriptionEditorEventHandlers);
this.subscriptionManagerFactory = Objects.requireNonNull(subscriptionManagerFactory);
this.representationRefreshPolicyRegistry = Objects.requireNonNull(representationRefreshPolicyRegistry);
this.subscriptionManagerFactory = Objects.requireNonNull(configuration.getSubscriptionManagerFactory());
this.representationRefreshPolicyRegistry = Objects.requireNonNull(configuration.getRepresentationRefreshPolicyRegistry());
}

@Override
Expand Down
Expand Up @@ -12,12 +12,14 @@
*******************************************************************************/
package org.eclipse.sirius.components.collaborative.formdescriptioneditors.handlers;

import java.util.List;
import java.util.Objects;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.sirius.components.collaborative.api.ChangeDescription;
import org.eclipse.sirius.components.collaborative.api.ChangeKind;
import org.eclipse.sirius.components.collaborative.api.Monitoring;
Expand All @@ -31,6 +33,7 @@
import org.eclipse.sirius.components.core.api.IObjectService;
import org.eclipse.sirius.components.core.api.IPayload;
import org.eclipse.sirius.components.core.api.SuccessPayload;
import org.eclipse.sirius.components.formdescriptioneditors.IWidgetDescriptionProvider;
import org.eclipse.sirius.components.view.FlexDirection;
import org.eclipse.sirius.components.view.FlexboxContainerDescription;
import org.eclipse.sirius.components.view.GroupDescription;
Expand All @@ -56,11 +59,14 @@ public class AddWidgetEventHandler implements IFormDescriptionEditorEventHandler

private final ICollaborativeFormDescriptionEditorMessageService messageService;

private final List<IWidgetDescriptionProvider> widgetDescriptionProviders;

private final Counter counter;

public AddWidgetEventHandler(IObjectService objectService, ICollaborativeFormDescriptionEditorMessageService messageService, MeterRegistry meterRegistry) {
public AddWidgetEventHandler(IObjectService objectService, ICollaborativeFormDescriptionEditorMessageService messageService, List<IWidgetDescriptionProvider> widgetDescriptionProviders, MeterRegistry meterRegistry) {
this.objectService = Objects.requireNonNull(objectService);
this.messageService = Objects.requireNonNull(messageService);
this.widgetDescriptionProviders = Objects.requireNonNull(widgetDescriptionProviders);

// @formatter:off
this.counter = Counter.builder(Monitoring.EVENT_HANDLER)
Expand Down Expand Up @@ -103,9 +109,9 @@ private boolean addWidget(IEditingContext editingContext, IFormDescriptionEditor
var optionalSelf = this.objectService.getObject(editingContext, containerId);
if (optionalSelf.isPresent()) {
Object container = optionalSelf.get();
EClassifier eClassifier = ViewPackage.eINSTANCE.getEClassifier(kind + "Description");
if (eClassifier instanceof EClass) {
var widgetDescription = ViewFactory.eINSTANCE.create((EClass) eClassifier);
EClassifier eClassifier = this.getWidgetDescriptionType(kind);
if (eClassifier instanceof EClass eClass) {
var widgetDescription = EcoreUtil.create(eClass);
if (widgetDescription instanceof FlexboxContainerDescription) {
((FlexboxContainerDescription) widgetDescription).setFlexDirection(FlexDirection.get(kind));
}
Expand All @@ -124,6 +130,17 @@ private boolean addWidget(IEditingContext editingContext, IFormDescriptionEditor
return success;
}


private EClassifier getWidgetDescriptionType(String kind) {
for (IWidgetDescriptionProvider widgetDescriptionProvider : this.widgetDescriptionProviders) {
var optionalType = widgetDescriptionProvider.getWidgetDescriptionType(kind);
if (optionalType.isPresent()) {
return optionalType.get();
}
}
return ViewPackage.eINSTANCE.getEClassifier(kind + "Description");
}

private void createStyle(WidgetDescription widgetDescription) {
EStructuralFeature styleFeature = widgetDescription.eClass().getEStructuralFeature("style");
if (styleFeature instanceof EReference) {
Expand Down
Expand Up @@ -14,6 +14,7 @@

import static org.assertj.core.api.Assertions.assertThat;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

Expand Down Expand Up @@ -50,7 +51,7 @@ public Optional<Object> getObject(IEditingContext editingContext, String objectI
return Optional.of(ViewFactory.eINSTANCE.createFlexboxContainerDescription());
}
};
var handler = new AddWidgetEventHandler(objectService, new ICollaborativeFormDescriptionEditorMessageService.NoOp(), new SimpleMeterRegistry());
var handler = new AddWidgetEventHandler(objectService, new ICollaborativeFormDescriptionEditorMessageService.NoOp(), List.of(), new SimpleMeterRegistry());
var input = new AddWidgetInput(UUID.randomUUID(), "editingContextId", "representationId", "containerId", "Checkbox", 0);

assertThat(handler.canHandle(input)).isTrue();
Expand Down
@@ -0,0 +1,26 @@
/*******************************************************************************
* Copyright (c) 2023 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.formdescriptioneditors;

import java.util.Optional;

import org.eclipse.emf.ecore.EClass;

/**
* Provides the EClass to use to represent a given kind of widget in a Form Description Editor.
*
* @author pcdavid
*/
public interface IWidgetDescriptionProvider {
Optional<EClass> getWidgetDescriptionType(String widgetKind);
}

0 comments on commit 92b4de2

Please sign in to comment.