org.eclipse.jface.databinding.fieldassist.ControlDecorationSupport.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jface.databinding.fieldassist.ControlDecorationSupport.java

Source

/*******************************************************************************
 * Copyright (c) 2009, 2015 Matthew Hall and others.
 *
 * 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:
 *     Matthew Hall - initial API and implementation (bug 268472)
 *     Matthew Hall - bug 300953
 *     Jeanderson Candido <http://jeandersonbc.github.io> - Bug 413611
 *     Simon Scholz <simon.scholz@vogella.com> - Bug 481620, 481358
 ******************************************************************************/

package org.eclipse.jface.databinding.fieldassist;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.databinding.ValidationStatusProvider;
import org.eclipse.core.databinding.observable.DisposeEvent;
import org.eclipse.core.databinding.observable.IDecoratingObservable;
import org.eclipse.core.databinding.observable.IDisposeListener;
import org.eclipse.core.databinding.observable.IObservable;
import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.list.IListChangeListener;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.list.ListChangeEvent;
import org.eclipse.core.databinding.observable.list.ListDiffVisitor;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.observable.value.IValueChangeListener;
import org.eclipse.core.databinding.observable.value.ValueChangeEvent;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.databinding.swt.ISWTObservable;
import org.eclipse.jface.databinding.viewers.IViewerObservable;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Widget;

/**
 * Decorates the underlying controls of the target observables of a
 * {@link ValidationStatusProvider} with {@link ControlDecoration}s mirroring
 * the current validation status. Only those target observables which implement
 * {@link ISWTObservable} or {@link IViewerObservable} are decorated.
 *
 * @since 1.4
 */
public class ControlDecorationSupport {
    /**
     * Creates a ControlDecorationSupport which observes the validation status
     * of the specified {@link ValidationStatusProvider}, and displays a
     * {@link ControlDecoration} over the underlying SWT control of all target
     * observables that implement {@link ISWTObservable} or
     * {@link IViewerObservable}.
     *
     * @param validationStatusProvider
     *            the {@link ValidationStatusProvider} to monitor.
     * @param position
     *            SWT alignment constant (e.g. SWT.LEFT | SWT.TOP) to use when
     *            constructing {@link ControlDecorationSupport}
     * @return a ControlDecorationSupport which observes the validation status
     *         of the specified {@link ValidationStatusProvider}, and displays a
     *         {@link ControlDecoration} over the underlying SWT control of all
     *         target observables that implement {@link ISWTObservable} or
     *         {@link IViewerObservable}.
     */
    public static ControlDecorationSupport create(ValidationStatusProvider validationStatusProvider, int position) {
        return create(validationStatusProvider, position, null, new ControlDecorationUpdater());
    }

    /**
     * Creates a ControlDecorationSupport which observes the given validation
     * status and displays a {@link ControlDecoration} over the underlying SWT
     * control of all target observables that implement {@link ISWTObservable}
     * or {@link IViewerObservable}.
     *
     * @param validationStatus
     *            an {@link IObservable} containing an {@link IStatus}, which
     *            will be tracked by the {@link ControlDecorationSupport}.
     * @param position
     *            SWT alignment constant (e.g. SWT.LEFT | SWT.TOP) to use when
     *            constructing {@link ControlDecorationSupport}
     * @param targetsToBeDecorated
     *            the target observables, which contain widget to be decorated
     *            according to the current validation status
     * @return a ControlDecorationSupport which observes the validation status
     *         and displays a {@link ControlDecoration} over the underlying SWT
     *         control of all target observables that implement
     *         {@link ISWTObservable} or {@link IViewerObservable}.
     * @since 1.8
     */
    public static ControlDecorationSupport create(IObservableValue<IStatus> validationStatus, int position,
            IObservable... targetsToBeDecorated) {
        return create(validationStatus, position, null, new ControlDecorationUpdater(),
                getObservableList(targetsToBeDecorated));
    }

    /**
     * Creates a ControlDecorationSupport which observes the given validation
     * status and displays a {@link ControlDecoration} over the underlying SWT
     * control of all target observables that implement {@link ISWTObservable}
     * or {@link IViewerObservable}.
     *
     * @param validationStatus
     *            an {@link IObservable} containing an {@link IStatus}, which
     *            will be tracked by the {@link ControlDecorationSupport}.
     * @param position
     *            SWT alignment constant (e.g. SWT.LEFT | SWT.TOP) to use when
     *            constructing {@link ControlDecorationSupport}
     * @param targetsToBeDecorated
     *            the target observables, which contain widget to be decorated
     *            according to the current validation status
     * @return a ControlDecorationSupport which observes the validation status
     *         and displays a {@link ControlDecoration} over the underlying SWT
     *         control of all target observables that implement
     *         {@link ISWTObservable} or {@link IViewerObservable}.
     * @since 1.8
     */
    public static ControlDecorationSupport create(IObservableValue<IStatus> validationStatus, int position,
            IObservableList<IObservable> targetsToBeDecorated) {
        return create(validationStatus, position, null, new ControlDecorationUpdater(), targetsToBeDecorated);
    }

    /**
     * Creates a ControlDecorationSupport which observes the validation status
     * of the specified {@link ValidationStatusProvider}, and displays a
     * {@link ControlDecoration} over the underlying SWT control of all target
     * observables that implement {@link ISWTObservable} or
     * {@link IViewerObservable}.
     *
     * @param validationStatusProvider
     *            the {@link ValidationStatusProvider} to monitor.
     * @param position
     *            SWT alignment constant (e.g. SWT.LEFT | SWT.TOP) to use when
     *            constructing {@link ControlDecoration} instances.
     * @param composite
     *            the composite to use when constructing
     *            {@link ControlDecoration} instances.
     * @return a ControlDecorationSupport which observes the validation status
     *         of the specified {@link ValidationStatusProvider}, and displays a
     *         {@link ControlDecoration} over the underlying SWT control of all
     *         target observables that implement {@link ISWTObservable} or
     *         {@link IViewerObservable}.
     */
    public static ControlDecorationSupport create(ValidationStatusProvider validationStatusProvider, int position,
            Composite composite) {
        return create(validationStatusProvider, position, composite, new ControlDecorationUpdater());
    }

    /**
     * Creates a ControlDecorationSupport which observes the validation status
     * and displays a {@link ControlDecoration} over the underlying SWT control
     * of all target observables that implement {@link ISWTObservable} or
     * {@link IViewerObservable}.
     *
     * @param validationStatus
     *            an {@link IObservable} containing an {@link IStatus}, which
     *            will be tracked by the {@link ControlDecorationSupport}.
     * @param position
     *            SWT alignment constant (e.g. SWT.LEFT | SWT.TOP) to use when
     *            constructing {@link ControlDecorationSupport}
     * @param targetsToBeDecorated
     *            the target observables, which contain widget to be decorated
     *            according to the current validation status
     * @param composite
     *            the composite to use when constructing
     *            {@link ControlDecoration} instances.
     * @return a ControlDecorationSupport which observes the validation status
     *         and displays a {@link ControlDecoration} over the underlying SWT
     *         control of all target observables that implement
     *         {@link ISWTObservable} or {@link IViewerObservable}.
     *
     * @since 1.8
     */
    public static ControlDecorationSupport create(IObservableValue<IStatus> validationStatus, int position,
            Composite composite, IObservable... targetsToBeDecorated) {
        return create(validationStatus, position, composite, new ControlDecorationUpdater(),
                getObservableList(targetsToBeDecorated));
    }

    /**
     * Creates a ControlDecorationSupport which observes the validation status
     * and displays a {@link ControlDecoration} over the underlying SWT control
     * of all target observables that implement {@link ISWTObservable} or
     * {@link IViewerObservable}.
     *
     * @param validationStatus
     *            an {@link IObservable} containing an {@link IStatus}, which
     *            will be tracked by the {@link ControlDecorationSupport}.
     * @param position
     *            SWT alignment constant (e.g. SWT.LEFT | SWT.TOP) to use when
     *            constructing {@link ControlDecorationSupport}
     * @param targetsToBeDecorated
     *            the target observables, which contain widget to be decorated
     *            according to the current validation status
     * @param composite
     *            the composite to use when constructing
     *            {@link ControlDecoration} instances.
     * @return a ControlDecorationSupport which observes the validation status
     *         and displays a {@link ControlDecoration} over the underlying SWT
     *         control of all target observables that implement
     *         {@link ISWTObservable} or {@link IViewerObservable}.
     * @since 1.8
     */
    public static ControlDecorationSupport create(IObservableValue<IStatus> validationStatus, int position,
            Composite composite, IObservableList<IObservable> targetsToBeDecorated) {
        return create(validationStatus, position, composite, new ControlDecorationUpdater(), targetsToBeDecorated);
    }

    /**
     * Creates a ControlDecorationSupport which observes the validation status
     * of the specified {@link ValidationStatusProvider}, and displays a
     * {@link ControlDecoration} over the underlying SWT control of all target
     * observables that implement {@link ISWTObservable} or
     * {@link IViewerObservable}.
     *
     * @param validationStatusProvider
     *            the {@link ValidationStatusProvider} to monitor.
     * @param position
     *            SWT alignment constant (e.g. SWT.LEFT | SWT.TOP) to use when
     *            constructing {@link ControlDecoration} instances.
     * @param composite
     *            the composite to use when constructing
     *            {@link ControlDecoration} instances.
     * @param updater
     *            custom strategy for updating the {@link ControlDecoration}(s)
     *            whenever the validation status changes.
     * @return a ControlDecorationSupport which observes the validation status
     *         of the specified {@link ValidationStatusProvider}, and displays a
     *         {@link ControlDecoration} over the underlying SWT control of all
     *         target observables that implement {@link ISWTObservable} or
     *         {@link IViewerObservable}.
     */
    public static ControlDecorationSupport create(ValidationStatusProvider validationStatusProvider, int position,
            Composite composite, ControlDecorationUpdater updater) {
        return create(validationStatusProvider.getValidationStatus(), position, composite, updater,
                validationStatusProvider.getTargets());
    }

    /**
     * Creates a ControlDecorationSupport which observes the validation status
     * and displays a {@link ControlDecoration} over the underlying SWT control
     * of all target observables that implement {@link ISWTObservable} or
     * {@link IViewerObservable}.
     *
     * @param validationStatus
     *            an {@link IObservable} containing an {@link IStatus}, which
     *            will be tracked by the {@link ControlDecorationSupport}.
     * @param position
     *            SWT alignment constant (e.g. SWT.LEFT | SWT.TOP) to use when
     *            constructing {@link ControlDecorationSupport}
     * @param composite
     *            the composite to use when constructing
     *            {@link ControlDecoration} instances.
     * @param updater
     *            custom strategy for updating the {@link ControlDecoration}(s)
     *            whenever the validation status changes.
     * @param targetsToBeDecorated
     *            the target observables, which contain widget to be decorated
     *            according to the current validation status
     * @return a ControlDecorationSupport which observes the validation status
     *         and displays a {@link ControlDecoration} over the underlying SWT
     *         control of all target observables that implement
     *         {@link ISWTObservable} or {@link IViewerObservable}.
     * @since 1.8
     */
    public static ControlDecorationSupport create(IObservableValue<IStatus> validationStatus, int position,
            Composite composite, ControlDecorationUpdater updater, IObservable... targetsToBeDecorated) {
        return create(validationStatus, position, composite, updater, getObservableList(targetsToBeDecorated));
    }

    /**
     * Creates a ControlDecorationSupport which observes the validation status
     * and displays a {@link ControlDecoration} over the underlying SWT control
     * of all target observables that implement {@link ISWTObservable} or
     * {@link IViewerObservable}.
     *
     * @param validationStatus
     *            an {@link IObservable} containing an {@link IStatus}, which
     *            will be tracked by the {@link ControlDecorationSupport}.
     * @param position
     *            SWT alignment constant (e.g. SWT.LEFT | SWT.TOP) to use when
     *            constructing {@link ControlDecorationSupport}
     * @param composite
     *            the composite to use when constructing
     *            {@link ControlDecoration} instances.
     * @param updater
     *            custom strategy for updating the {@link ControlDecoration}(s)
     *            whenever the validation status changes.
     * @param targetsToBeDecorated
     *            the target observables, which contain widget to be decorated
     *            according to the current validation status
     * @return a ControlDecorationSupport which observes the validation status
     *         and displays a {@link ControlDecoration} over the underlying SWT
     *         control of all target observables that implement
     *         {@link ISWTObservable} or {@link IViewerObservable}.
     * @since 1.8
     */
    public static ControlDecorationSupport create(IObservableValue<IStatus> validationStatus, int position,
            Composite composite, ControlDecorationUpdater updater,
            IObservableList<IObservable> targetsToBeDecorated) {
        return new ControlDecorationSupport(validationStatus, targetsToBeDecorated, position, composite, updater);
    }

    private final int position;
    private final Composite composite;
    private final ControlDecorationUpdater updater;

    private IObservableValue<IStatus> validationStatus;
    private IObservableList<IObservable> targets;

    private IDisposeListener disposeListener = new IDisposeListener() {
        @Override
        public void handleDispose(DisposeEvent staleEvent) {
            dispose();
        }
    };

    private IValueChangeListener<IStatus> statusChangeListener = new IValueChangeListener<IStatus>() {
        @Override
        public void handleValueChange(ValueChangeEvent<? extends IStatus> event) {
            statusChanged(validationStatus.getValue());
        }
    };

    private IListChangeListener<IObservable> targetsChangeListener = new IListChangeListener<IObservable>() {

        @Override
        public void handleListChange(ListChangeEvent<? extends IObservable> event) {
            event.diff.accept(new TargetsListDiffAdvisor<>());
            statusChanged(validationStatus.getValue());
        }

    };

    private static class TargetDecoration {
        public final IObservable target;
        public final ControlDecoration decoration;

        TargetDecoration(IObservable target, ControlDecoration decoration) {
            this.target = target;
            this.decoration = decoration;
        }
    }

    private class TargetsListDiffAdvisor<E extends IObservable> extends ListDiffVisitor<E> {

        @Override
        public void handleAdd(int index, E element) {
            targetAdded(element);
        }

        @Override
        public void handleRemove(int index, E element) {
            targetRemoved(element);
        }

    }

    private List<TargetDecoration> targetDecorations;

    private ControlDecorationSupport(IObservableValue<IStatus> validationStatus,
            IObservableList<IObservable> targetsToBeDecorated, int position, Composite composite,
            ControlDecorationUpdater updater) {
        this.position = position;
        this.composite = composite;
        this.updater = updater;

        this.validationStatus = validationStatus;
        Assert.isTrue(!this.validationStatus.isDisposed());

        this.targets = targetsToBeDecorated;
        Assert.isTrue(!this.targets.isDisposed());

        this.targetDecorations = new ArrayList<>();

        validationStatus.addDisposeListener(disposeListener);
        validationStatus.addValueChangeListener(statusChangeListener);

        targets.addDisposeListener(disposeListener);
        targets.addListChangeListener(targetsChangeListener);

        for (Object name : targets)
            targetAdded((IObservable) name);

        statusChanged(validationStatus.getValue());
    }

    private void targetAdded(IObservable target) {
        Control control = findControl(target);
        if (control != null)
            targetDecorations
                    .add(new TargetDecoration(target, new ControlDecoration(control, position, composite)));
    }

    private void targetRemoved(IObservable target) {
        for (Iterator<TargetDecoration> it = targetDecorations.iterator(); it.hasNext();) {
            TargetDecoration targetDecoration = it.next();
            if (targetDecoration.target == target) {
                targetDecoration.decoration.dispose();
                it.remove();
            }
        }
    }

    private Control findControl(IObservable target) {
        if (target instanceof ISWTObservable) {
            Widget widget = ((ISWTObservable) target).getWidget();
            if (widget instanceof Control)
                return (Control) widget;
        }

        if (target instanceof IViewerObservable) {
            Viewer viewer = ((IViewerObservable) target).getViewer();
            return viewer.getControl();
        }

        if (target instanceof IDecoratingObservable) {
            IObservable decorated = ((IDecoratingObservable) target).getDecorated();
            Control control = findControl(decorated);
            if (control != null)
                return control;
        }

        if (target instanceof IObserving) {
            Object observed = ((IObserving) target).getObserved();
            if (observed instanceof IObservable)
                return findControl((IObservable) observed);
        }

        return null;
    }

    private void statusChanged(IStatus status) {
        for (TargetDecoration targetDecoration : targetDecorations) {
            ControlDecoration decoration = targetDecoration.decoration;
            updater.update(decoration, status);
        }
    }

    private static IObservableList<IObservable> getObservableList(IObservable[] observables) {
        IObservableList<IObservable> observableList = new WritableList<>();
        java.util.Collections.addAll(observableList, observables);

        return observableList;
    }

    /**
     * Disposes this ControlDecorationSupport, including all control decorations
     * managed by it. A ControlDecorationSupport is automatically disposed when
     * its target ValidationStatusProvider is disposed.
     */
    public void dispose() {
        if (validationStatus != null) {
            validationStatus.removeDisposeListener(disposeListener);
            validationStatus.removeValueChangeListener(statusChangeListener);
            validationStatus = null;
        }

        if (targets != null) {
            targets.removeDisposeListener(disposeListener);
            targets.removeListChangeListener(targetsChangeListener);
            targets = null;
        }

        disposeListener = null;
        statusChangeListener = null;
        targetsChangeListener = null;

        if (targetDecorations != null) {
            for (TargetDecoration targetDecoration : targetDecorations) {
                targetDecoration.decoration.dispose();
            }
            targetDecorations.clear();
            targetDecorations = null;
        }
    }
}