/******************************************************************************* * Copyright (c) 2016 Obeo. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Obeo - initial API and implementation *******************************************************************************/ package org.eclipse.eef.ide.ui.internal.widgets; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.core.runtime.IStatus; import org.eclipse.eef.EEFRadioDescription; import org.eclipse.eef.EEFWidgetDescription; import org.eclipse.eef.EefPackage; import org.eclipse.eef.common.ui.api.EEFWidgetFactory; import org.eclipse.eef.common.ui.api.IEEFFormContainer; import org.eclipse.eef.core.api.EEFExpressionUtils; import org.eclipse.eef.core.api.EEFExpressionUtils.EEFSelect; import org.eclipse.eef.core.api.EditingContextAdapter; import org.eclipse.eef.core.api.controllers.EEFControllersFactory; import org.eclipse.eef.core.api.controllers.IEEFRadioController; import org.eclipse.eef.core.api.controllers.IEEFWidgetController; import org.eclipse.eef.core.api.utils.EvalFactory; import org.eclipse.eef.ide.ui.api.widgets.AbstractEEFWidgetLifecycleManager; import org.eclipse.eef.ide.ui.internal.EEFIdeUiPlugin; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.sirius.common.interpreter.api.IInterpreter; import org.eclipse.sirius.common.interpreter.api.IVariableManager; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.forms.widgets.FormToolkit; /** * This class will be used in order to manager the lifecycle of a radio button. * * @author mbats */ public class EEFRadioLifecycleManager extends AbstractEEFWidgetLifecycleManager { /** * The description. */ private EEFRadioDescription description; /** * The radio group viewer. */ private RadioGroupViewer radioGroupViewer; /** * The radio group. */ private RadioGroup radioGroup; /** * The controller. */ private IEEFRadioController controller; /** * The listener on the combo. */ private SelectionListener selectionListener; /** * Used to make the SelectionListener reentrant, to avoid infinite loops when we need to revert the UI state on * error (as reverting the UI re-triggers the SelectionListener). */ private AtomicBoolean updateInProgress = new AtomicBoolean(false); /** * The reference value of the selection, as last rendered from the state of the actual model. */ private ISelection referenceSelection; /** * The constructor. * * @param description * The description * @param variableManager * The variable manager * @param interpreter * The interpreter * @param editingContextAdapter * The editing context adapter */ public EEFRadioLifecycleManager(EEFRadioDescription description, IVariableManager variableManager, IInterpreter interpreter, EditingContextAdapter editingContextAdapter) { super(variableManager, interpreter, editingContextAdapter); this.description = description; } /** * {@inheritDoc} * * @see org.eclipse.eef.ide.ui.api.widgets.AbstractEEFWidgetLifecycleManager#createMainControl(org.eclipse.swt.widgets.Composite, * org.eclipse.eef.common.ui.api.IEEFFormContainer) */ @Override protected void createMainControl(Composite parent, IEEFFormContainer formContainer) { EEFWidgetFactory widgetFactory = formContainer.getWidgetFactory(); this.radioGroupViewer = new RadioGroupViewer(parent, widgetFactory, this.description.getNumberOfColumns()); this.radioGroup = radioGroupViewer.getRadioGroup(); GridData gridData = new GridData(); gridData.horizontalIndent = VALIDATION_MARKER_OFFSET; this.radioGroup.setLayoutData(gridData); this.radioGroupViewer.setContentProvider(ArrayContentProvider.getInstance()); this.radioGroupViewer.setLabelProvider(new EEFRadioLabelProvider()); this.radioGroupViewer.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER); widgetFactory.paintBordersFor(parent); this.controller = new EEFControllersFactory().createRadioController(this.description, this.variableManager, this.interpreter, this.editingContextAdapter); } /** * {@inheritDoc} * * @see org.eclipse.eef.ide.ui.api.widgets.AbstractEEFWidgetLifecycleManager#getController() */ @Override protected IEEFWidgetController getController() { return this.controller; } /** * {@inheritDoc} * * @see org.eclipse.eef.ide.ui.internal.widgets.AbstractEEFWidgetLifecycleManager#getWidgetDescription() */ @Override protected EEFWidgetDescription getWidgetDescription() { return this.description; } /** * {@inheritDoc} * * @see org.eclipse.eef.ide.ui.api.widgets.AbstractEEFWidgetLifecycleManager#getValidationControl() */ @Override protected Control getValidationControl() { return this.radioGroup; } /** * {@inheritDoc} * * @see org.eclipse.eef.ide.ui.api.widgets.IEEFLifecycleManager#aboutToBeShown() */ @Override public void aboutToBeShown() { super.aboutToBeShown(); // UI edited by user => update model if possible, revert UI change otherwise this.selectionListener = new SelectionListener() { @Override public void widgetSelected(SelectionEvent e) { if (!updateInProgress.compareAndSet(false, true)) { try { IStructuredSelection selection = getStructuredSelection(radioGroupViewer); Object newValue = selection.getFirstElement(); IStatus result = controller.updateValue(newValue); if (result != null && result.getSeverity() == IStatus.ERROR && referenceSelection != null) { EEFIdeUiPlugin.INSTANCE.log(result); radioGroupViewer.setSelection(referenceSelection); } else { refresh(); } } finally { updateInProgress.set(false); } } } @Override public void widgetDefaultSelected(SelectionEvent e) { // Nothing to do } }; this.radioGroup.addSelectionListener(this.selectionListener); // Set radio group value this.controller.onNewValue((value) -> { if (!this.radioGroup.isDisposed()) { final ISelection selection; if (value != null) { selection = new StructuredSelection(value); } else { selection = null; } this.radioGroupViewer.setSelection(selection); this.referenceSelection = selection; if (!this.radioGroup.isEnabled()) { this.radioGroup.setEnabled(true); } } }); // Set radio group items this.controller.onNewCandidates((candidates) -> { if (!this.radioGroup.isDisposed()) { if (candidates != null) { this.radioGroupViewer.setInput(candidates.toArray()); } else { this.radioGroupViewer.setInput(null); } if (!this.radioGroup.isEnabled()) { this.radioGroup.setEnabled(true); } this.radioGroupViewer.refresh(true); } }); } /** * {@inheritDoc} * * @see org.eclipse.eef.ide.ui.api.widgets.IEEFLifecycleManager#aboutToBeHidden() */ @Override public void aboutToBeHidden() { super.aboutToBeHidden(); if (!this.radioGroup.isDisposed()) { this.radioGroup.removeSelectionListener(this.selectionListener); } this.controller.removeNewValueConsumer(); this.controller.removeNewCandidatesConsumer(); } /** * {@inheritDoc} * * @see org.eclipse.eef.ide.ui.api.widgets.AbstractEEFWidgetLifecycleManager#setEnabled(boolean) */ @Override protected void setEnabled(boolean isEnabled) { if (!this.radioGroup.isDisposed()) { this.radioGroup.setEnabled(isEnabled); } } /** * Radio widget label provider. * * @author mbats */ private final class EEFRadioLabelProvider extends LabelProvider { @Override public String getText(Object element) { String expression = description.getCandidateDisplayExpression(); EAttribute eAttribute = EefPackage.Literals.EEF_RADIO_DESCRIPTION__CANDIDATE_DISPLAY_EXPRESSION; Map<String, Object> variables = new HashMap<String, Object>(); variables.put(EEFExpressionUtils.SELF, variableManager.getVariables().get(EEFExpressionUtils.SELF)); variables.put(EEFExpressionUtils.INPUT, variableManager.getVariables().get(EEFExpressionUtils.INPUT)); variables.put(EEFSelect.CANDIDATE, element); return EvalFactory.of(EEFRadioLifecycleManager.this.interpreter, variables).logIfInvalidType(String.class).logIfBlank(eAttribute) .evaluate(expression); } } }