com.microsoft.tfs.client.common.ui.framework.selection.SwitchingSelectionProvider.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.tfs.client.common.ui.framework.selection.SwitchingSelectionProvider.java

Source

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See License.txt in the repository root.

package com.microsoft.tfs.client.common.ui.framework.selection;

import org.eclipse.jface.viewers.IPostSelectionProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;

import com.microsoft.tfs.util.listeners.SingleListenerFacade;

/**
 * <p>
 * A {@link SwitchingSelectionProvider} is used when a control has multiple
 * selection providers, only one of which is active at a time, and wants to
 * present the facade of a single selection provider to clients. The control
 * presents a {@link SwitchingSelectionProvider} as that facade. When the actual
 * selection provider changes, the control calls
 * {@link #setSelectionProvider(ISelectionProvider)}.
 * </p>
 *
 * <p>
 * It is possible for a {@link SwitchingSelectionProvider} to have no current
 * selection provider. This is the case when a
 * {@link SwitchingSelectionProvider} is first created or when you pass
 * <code>null</code> to {@link #setSelectionProvider(ISelectionProvider)}.
 * </p>
 *
 * <p>
 * {@link SwitchingSelectionProvider} is currently oriented toward
 * {@link IStructuredSelection}-based selection providers. When it has no
 * current selection provider, {@link StructuredSelection#EMPTY} will be used as
 * the current selection.
 * </p>
 *
 * <p>
 * This class is useful for implementing a view that has multiple child content
 * areas, each with a different selection provider. A view must register only a
 * single selection provider with the view site, and should not change that
 * selection provider once registered.
 * </p>
 *
 * @see ISelectionProvider
 * @see IStructuredSelection
 */
public class SwitchingSelectionProvider implements IPostSelectionProvider {
    private final BroadcastingSelectionChangedListener selectionChangedListener;
    private final BroadcastingSelectionChangedListener postSelectionChangedListener;

    private ISelectionProvider currentWrappedProvider;
    private final Object currentWrappedProviderLock = new Object();

    /**
     * Creates a new {@link SwitchingSelectionProvider} that initially has no
     * selection provider. To set a selection provider, call
     * {@link #setSelectionProvider(ISelectionProvider)}.
     */
    public SwitchingSelectionProvider() {
        selectionChangedListener = new BroadcastingSelectionChangedListener(this);
        postSelectionChangedListener = new BroadcastingSelectionChangedListener(this);
    }

    /**
     * Sets a new {@link ISelectionProvider} for this
     * {@link SwitchingSelectionProvider}. Any {@link ISelectionChangedListener}
     * s that are registered with this {@link SwitchingSelectionProvider} will
     * receive {@link SelectionChangedEvent}s. The new
     * {@link ISelectionProvider} may be <code>null</code>.
     *
     * @param selectionProvider
     *        a new {@link ISelectionProvider} to use (may be <code>null</code>)
     */
    public void setSelectionProvider(final ISelectionProvider selectionProvider) {
        synchronized (currentWrappedProviderLock) {
            if (currentWrappedProvider != null) {
                currentWrappedProvider.removeSelectionChangedListener(selectionChangedListener);
                if (currentWrappedProvider instanceof IPostSelectionProvider) {
                    ((IPostSelectionProvider) currentWrappedProvider)
                            .removePostSelectionChangedListener(postSelectionChangedListener);
                }
            }

            currentWrappedProvider = selectionProvider;

            if (selectionProvider != null) {
                selectionProvider.addSelectionChangedListener(selectionChangedListener);
                if (selectionProvider instanceof IPostSelectionProvider) {
                    ((IPostSelectionProvider) selectionProvider)
                            .addPostSelectionChangedListener(postSelectionChangedListener);
                }
            }

            final ISelection selection = (selectionProvider != null ? selectionProvider.getSelection()
                    : StructuredSelection.EMPTY);
            selectionChangedListener.fireChildListeners(selection);
            postSelectionChangedListener.fireChildListeners(selection);
        }
    }

    /*
     * BEGIN: IPostSelectionProvider implementation
     */

    /*
     * (non-Javadoc)
     *
     * @seeorg.eclipse.jface.viewers.IPostSelectionProvider#
     * addPostSelectionChangedListener
     * (org.eclipse.jface.viewers.ISelectionChangedListener)
     */
    @Override
    public void addPostSelectionChangedListener(final ISelectionChangedListener listener) {
        postSelectionChangedListener.addChildListener(listener);
    }

    /*
     * (non-Javadoc)
     *
     * @seeorg.eclipse.jface.viewers.IPostSelectionProvider#
     * removePostSelectionChangedListener
     * (org.eclipse.jface.viewers.ISelectionChangedListener)
     */
    @Override
    public void removePostSelectionChangedListener(final ISelectionChangedListener listener) {
        postSelectionChangedListener.removeChildListener(listener);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener
     * (org.eclipse.jface.viewers.ISelectionChangedListener)
     */
    @Override
    public void addSelectionChangedListener(final ISelectionChangedListener listener) {
        selectionChangedListener.addChildListener(listener);
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.jface.viewers.ISelectionProvider#
     * removeSelectionChangedListener
     * (org.eclipse.jface.viewers.ISelectionChangedListener)
     */
    @Override
    public void removeSelectionChangedListener(final ISelectionChangedListener listener) {
        selectionChangedListener.removeChildListener(listener);
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection()
     */
    @Override
    public ISelection getSelection() {
        synchronized (currentWrappedProviderLock) {
            if (currentWrappedProvider != null) {
                return currentWrappedProvider.getSelection();
            }
        }

        return StructuredSelection.EMPTY;
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * org.eclipse.jface.viewers.ISelectionProvider#setSelection(org.eclipse
     * .jface.viewers.ISelection)
     */
    @Override
    public void setSelection(final ISelection selection) {
        synchronized (currentWrappedProviderLock) {
            if (currentWrappedProvider != null) {
                currentWrappedProvider.setSelection(selection);
            }
        }
    }

    /*
     * END: IPostSelectionProvider implementation
     */

    /**
     * A {@link BroadcastingSelectionChangedListener} serves a few purposes:
     * <ul>
     * <li>First, it is an {@link ISelectionChangedListener} and is added to the
     * current delegate {@link ISelectionProvider} that this
     * {@link SwitchingSelectionProvider} wraps.</li>
     * <li>Secondly, it holds any {@link ISelectionProvider}s that are
     * externally registered with this {@link SwitchingSelectionProvider}.</li>
     * <li>Finally, when it receives a {@link SelectionChangedEvent}, it
     * broadcasts a new {@link SelectionChangedEvent} to any child
     * {@link ISelectionChangedListener}s registered with it.</li>
     * </ul>
     */
    private static class BroadcastingSelectionChangedListener implements ISelectionChangedListener {
        private final SingleListenerFacade broadcastTargets;
        private final ISelectionProvider provider;

        public BroadcastingSelectionChangedListener(final ISelectionProvider provider) {
            this.provider = provider;
            broadcastTargets = new SingleListenerFacade(ISelectionChangedListener.class);
        }

        public void addChildListener(final ISelectionChangedListener listener) {
            broadcastTargets.addListener(listener);
        }

        public void removeChildListener(final ISelectionChangedListener listener) {
            broadcastTargets.removeListener(listener);
        }

        @Override
        public void selectionChanged(final SelectionChangedEvent event) {
            fireChildListeners(event.getSelection());
        }

        public void fireChildListeners(final ISelection selection) {
            final ISelectionChangedListener listener = (ISelectionChangedListener) broadcastTargets.getListener();
            listener.selectionChanged(new SelectionChangedEvent(provider, selection));
        }
    }
}