org.eclipse.emf.ecp.edit.internal.swt.reference.LinkControl.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.emf.ecp.edit.internal.swt.reference.LinkControl.java

Source

/*******************************************************************************
 * 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 v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * 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.Activator;
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.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.
 *
 * @author Eugen Neufeld
 *
 */
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,
                Activator.getDefault().getEMFFormsEditSupport(), Activator.getDefault().getEMFFormsLabelProvider(),
                getService(ReferenceService.class), Activator.getDefault().getReportService(),
                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;
    }
}