Skip to content

Content of file LinkControl.java

/*******************************************************************************
 * Copyright (c) 2011-2015 EclipseSource Muenchen GmbH and others.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 * Eugen Neufeld - initial API and implementation
 * Philip Langer - bug fix 460968
 *
 *******************************************************************************/
package org.eclipse.emf.ecp.edit.internal.swt.reference;

import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature.Setting;
import org.eclipse.emf.ecp.edit.internal.swt.SWTImageHelper;
import org.eclipse.emf.ecp.edit.internal.swt.controls.SingleControl;
import org.eclipse.emf.ecp.edit.spi.ReferenceService;
import org.eclipse.emf.ecp.edit.spi.swt.reference.AddReferenceAction;
import org.eclipse.emf.ecp.edit.spi.swt.reference.DeleteReferenceAction;
import org.eclipse.emf.ecp.edit.spi.swt.reference.NewReferenceAction;
import org.eclipse.emf.ecp.edit.spi.util.ECPModelElementChangeListener;
import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
import org.eclipse.emfforms.spi.common.report.ReportService;
import org.eclipse.emfforms.spi.core.services.editsupport.EMFFormsEditSupport;
import org.eclipse.emfforms.spi.core.services.label.EMFFormsLabelProvider;
import org.eclipse.emfforms.spi.localization.LocalizationServiceHelper;
import org.eclipse.jface.databinding.swt.WidgetProperties;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;

/**
 * This class defines a Control which is used for displaying {@link org.eclipse.emf.ecore.EStructuralFeature
 * EStructuralFeature}s which have a reference.
 *
 * @deprecated Use LinkControlSWTRenderer instead
 * @author Eugen Neufeld
 *
 */
@Deprecated
public class LinkControl extends SingleControl {

	private Composite linkComposite;

	private Link hyperlink;

	private Label imageHyperlink;

	/**
	 * The {@link ComposedAdapterFactory} used by the control.
	 */
	private ComposedAdapterFactory composedAdapterFactory;

	private ECPModelElementChangeListener modelElementChangeListener;

	private Label unsetLabel;

	private StackLayout stackLayout;

	private Composite mainComposite;

	private Button[] buttons;
	/**
	 * The {@link AdapterFactoryItemDelegator} used by this control.
	 */
	private AdapterFactoryItemDelegator adapterFactoryItemDelegator;

	@Override
	protected void fillControlComposite(Composite composite) {
		int numColumns = 1 + getNumButtons();
		if (isEmbedded()) {
			numColumns = 1;
		}
		if (!isEmbedded() && getFirstStructuralFeature().isUnsettable()) {
			numColumns++;
		}
		final Composite parent = new Composite(composite, SWT.NONE);
		parent.setBackground(composite.getBackground());
		GridLayoutFactory.fillDefaults().numColumns(numColumns).spacing(0, 0).equalWidth(false).applyTo(parent);
		GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.BEGINNING).applyTo(parent);
		mainComposite = new Composite(parent, SWT.NONE);
		mainComposite.setBackground(parent.getBackground());
		GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.CENTER).applyTo(mainComposite);

		stackLayout = new StackLayout();
		mainComposite.setLayout(stackLayout);

		unsetLabel = new Label(mainComposite, SWT.NONE);
		unsetLabel.setText(LocalizationServiceHelper.getString(getClass(), ReferenceMessageKeys.LinkControl_NotSet));
		unsetLabel.setBackground(mainComposite.getBackground());
		unsetLabel.setForeground(getSystemColor(SWT.COLOR_DARK_GRAY));
		unsetLabel.setAlignment(SWT.CENTER);

		linkComposite = new Composite(mainComposite, SWT.NONE);
		GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false).applyTo(linkComposite);
		linkComposite.setBackground(mainComposite.getBackground());

		createHyperlink();
		GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.CENTER).applyTo(linkComposite);
		if (getFirstSetting().isSet()) {
			stackLayout.topControl = linkComposite;
		} else {
			stackLayout.topControl = unsetLabel;
		}
		if (!isEmbedded()) {
			buttons = createButtons(parent);
		}
	}

	/**
	 *
	 * @return number of buttons added by the link control.
	 */
	protected int getNumButtons() {
		return 3;
	}

	/**
	 * Creates the buttons to delete a reference, add one to an existing and add a new element to be referenced.
	 *
	 * @param composite the {@link Composite} to place the buttons on
	 * @return An array of buttons
	 */
	protected Button[] createButtons(Composite composite) {
		final Button[] buttons = new Button[3];
		final Setting setting = getFirstSetting();
		buttons[0] = createButtonForAction(new DeleteReferenceAction(getEditingDomain(getFirstSetting()), setting,
			getService(ReferenceService.class)), composite);
		buttons[1] = createButtonForAction(new AddReferenceAction(getEditingDomain(getFirstSetting()), setting,
			getItemPropertyDescriptor(setting), getService(ReferenceService.class)), composite);
		buttons[2] = createButtonForAction(new NewReferenceAction(getEditingDomain(getFirstSetting()), setting,
			getViewModelContext().getService(EMFFormsEditSupport.class),
			getViewModelContext().getService(EMFFormsLabelProvider.class),
			getService(ReferenceService.class), getViewModelContext().getService(ReportService.class),
			getDomainModelReference(),
			getViewModelContext().getDomainModel()), composite);
		return buttons;
	}

	private void createHyperlink() {
		setComposedAdapterFactory(new ComposedAdapterFactory(new AdapterFactory[] {
			new ReflectiveItemProviderAdapterFactory(),
			new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE) }));
		setAdapterFactoryItemDelegator(new AdapterFactoryItemDelegator(getComposedAdapterFactory()));
		// adapterFactoryLabelProvider = new AdapterFactoryLabelProvider(composedAdapterFactory);
		// shortLabelProvider = new ShortLabelProvider(composedAdapterFactory);

		imageHyperlink = new Label(linkComposite, SWT.NONE);
		imageHyperlink.setBackground(linkComposite.getBackground());

		hyperlink = new Link(linkComposite, SWT.NONE);
		hyperlink.setData(CUSTOM_VARIANT, "org_eclipse_emf_ecp_control_reference"); //$NON-NLS-1$
		hyperlink.setBackground(linkComposite.getBackground());
		hyperlink.addSelectionListener(new SelectionAdapter() {

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				super.widgetDefaultSelected(e);
				widgetSelected(e);
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				super.widgetSelected(e);
				linkClicked((EObject) getModelValue().getValue());
			}

		});
		GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.BEGINNING).applyTo(hyperlink);

	}

	/**
	 * This code is called whenever the link of the link widget is clicked. You can overwrite this to change the
	 * behavior.
	 *
	 * @param value the EObject that is linked
	 */
	protected void linkClicked(EObject value) {
		getService(ReferenceService.class).openInNewContext(value);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setEditable(boolean isEditable) {
		if (!isEmbedded()) {
			for (final Button button : buttons) {
				button.setVisible(isEditable);
			}
		}
		mainComposite.getParent().layout();
	}

	@Override
	public Binding bindValue() {

		final IObservableValue value = WidgetProperties.text().observe(hyperlink);
		getDataBindingContext().bindValue(value, getModelValue(), createValueExtractingUpdateStrategy(),
			new UpdateValueStrategy() {
				@Override
				public Object convert(Object value) {
					updateChangeListener((EObject) value);
					return "<a>" + getLinkText(value) + "</a>"; //$NON-NLS-1$ //$NON-NLS-2$
				}
			});

		final IObservableValue tooltipValue = WidgetProperties.tooltipText().observe(hyperlink);
		getDataBindingContext().bindValue(tooltipValue, getModelValue(),
			createValueExtractingUpdateStrategy(),
			new UpdateValueStrategy() {
				@Override
				public Object convert(Object value) {
					return getLinkText(value);
				}
			});

		final IObservableValue imageValue = WidgetProperties.image().observe(imageHyperlink);
		getDataBindingContext().bindValue(imageValue, getModelValue(),
			new UpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER),
			new UpdateValueStrategy() {
@Override public Object convert(Object value) { return getImage(value); } }); final IObservableValue deleteButtonEnablement = WidgetProperties.enabled().observe(getDeleteButton()); getDataBindingContext().bindValue(deleteButtonEnablement, getModelValue(), createValueExtractingUpdateStrategy(), new UpdateValueStrategy() { @Override public Object convert(Object value) { return value != null; } }); return null; } private UpdateValueStrategy createValueExtractingUpdateStrategy() { return new UpdateValueStrategy() { @Override public Object convert(Object value) { return getModelValue().getValue(); } }; } /** * Returns the image to be used for the given linked {@code value}. * * @param value the value * @return The image. */ protected Object getImage(Object value) { final Object image = getAdapterFactoryItemDelegator().getImage(value); return SWTImageHelper.getImage(image); } /** * Returns the link text to be used for the given linked {@code value}. * * @param value the value * @return The link text. */ protected Object getLinkText(Object value) { final String linkName = getAdapterFactoryItemDelegator().getText(value); return linkName == null ? "" : linkName; //$NON-NLS-1$ } /** * Returns the delete button of this control. * * @return The delete button of this control. */ protected Button getDeleteButton() { return buttons[0]; } /** * {@inheritDoc} * * @see org.eclipse.emf.ecp.edit.internal.swt.controls.SingleControl#updateValidationColor(org.eclipse.swt.graphics.Color) */ @Override protected void updateValidationColor(Color color) { if (hyperlink != null) { hyperlink.setBackground(color); } } private void updateChangeListener(final EObject value) { if (modelElementChangeListener != null) { if (modelElementChangeListener.getTarget().equals(value)) { return; } modelElementChangeListener.remove(); modelElementChangeListener = null; } if (value == null) { if (stackLayout.topControl != unsetLabel) { stackLayout.topControl = unsetLabel; mainComposite.layout(); } } else { if (stackLayout.topControl != linkComposite) { stackLayout.topControl = linkComposite; mainComposite.layout(); } modelElementChangeListener = new ECPModelElementChangeListener(value) { @Override public void onChange(Notification notification) { Display.getDefault().syncExec(new Runnable() { @Override public void run() { getDataBindingContext().updateTargets(); linkComposite.layout(); } }); } }; } } @Override public void dispose() { // adapterFactoryItemDelegator.dispose(); getComposedAdapterFactory().dispose(); // shortLabelProvider.dispose(); if (modelElementChangeListener != null) { modelElementChangeListener.remove(); } hyperlink.dispose(); super.dispose(); } /* * (non-Javadoc) * @see org.eclipse.emf.ecp.edit.internal.swt.controls.SingleControl#getUnsetLabelText() */ @Override protected String getUnsetLabelText() { return LocalizationServiceHelper .getString(getClass(), ReferenceMessageKeys.LinkControl_NoLinkSetClickToSetLink); } /* * (non-Javadoc) * @see org.eclipse.emf.ecp.edit.internal.swt.controls.SingleControl#getUnsetButtonTooltip() */ @Override protected String getUnsetButtonTooltip() { return LocalizationServiceHelper.getString(getClass(), ReferenceMessageKeys.LinkControl_UnsetLink); } /* * (non-Javadoc) * @see org.eclipse.emf.ecp.edit.internal.swt.util.SWTControl#getControlForTooltip() */ @Override protected Control[] getControlsForTooltip() { // return new Control[] { hyperlink, imageHyperlink }; return new Control[0]; } /** * @return the adapterFactoryItemDelegator */ public AdapterFactoryItemDelegator getAdapterFactoryItemDelegator() { return adapterFactoryItemDelegator; } /** * @param adapterFactoryItemDelegator the adapterFactoryItemDelegator to set */ public void setAdapterFactoryItemDelegator(AdapterFactoryItemDelegator adapterFactoryItemDelegator) { this.adapterFactoryItemDelegator = adapterFactoryItemDelegator; } /** * @return the composedAdapterFactory */ public ComposedAdapterFactory getComposedAdapterFactory() { return composedAdapterFactory; } /** * @param composedAdapterFactory the composedAdapterFactory to set */ public void setComposedAdapterFactory(ComposedAdapterFactory composedAdapterFactory) { this.composedAdapterFactory = composedAdapterFactory; } }