| /******************************************************************************* |
| * Copyright (c) 2006, 2016 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jface.internal.text.revisions; |
| |
| import org.eclipse.core.runtime.ListenerList; |
| |
| 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 org.eclipse.jface.text.ITextSelection; |
| import org.eclipse.jface.text.ITextViewer; |
| import org.eclipse.jface.text.revisions.Revision; |
| |
| /** |
| * A selection provider for annotate revisions. Selections of a revision can currently happen in |
| * following ways - note that this list may be changed in the future: |
| * <ul> |
| * <li>when the user clicks the revision ruler with the mouse</li> |
| * <li>when the caret is moved to a revision's line (only on post-selection)</li> |
| * </ul> |
| * <p> |
| * Calling {@link #setSelection(ISelection)} will set the current sticky revision on the ruler. |
| * </p> |
| * |
| * @since 3.2 |
| */ |
| public final class RevisionSelectionProvider implements ISelectionProvider { |
| |
| /** |
| * Post selection listener on the viewer that remembers the selection provider it is registered |
| * with. |
| */ |
| private final class PostSelectionListener implements ISelectionChangedListener { |
| private final IPostSelectionProvider fPostProvider; |
| |
| public PostSelectionListener(IPostSelectionProvider postProvider) { |
| postProvider.addPostSelectionChangedListener(this); |
| fPostProvider= postProvider; |
| } |
| |
| @Override |
| public void selectionChanged(SelectionChangedEvent event) { |
| ISelection selection= event.getSelection(); |
| if (selection instanceof ITextSelection) { |
| ITextSelection ts= (ITextSelection) selection; |
| int offset= ts.getOffset(); |
| setSelectedRevision(fPainter.getRevision(offset)); |
| } |
| |
| } |
| |
| public void dispose() { |
| fPostProvider.removePostSelectionChangedListener(this); |
| } |
| } |
| |
| private final RevisionPainter fPainter; |
| |
| private final ListenerList<ISelectionChangedListener> fListeners= new ListenerList<>(); |
| |
| /** |
| * The text viewer once we are installed, <code>null</code> if not installed. |
| */ |
| private ITextViewer fViewer; |
| /** |
| * The selection listener on the viewer, or <code>null</code>. |
| */ |
| private PostSelectionListener fSelectionListener; |
| /** |
| * The last selection, or <code>null</code>. |
| */ |
| private Revision fSelection; |
| /** |
| * Incoming selection changes are ignored while sending out events. |
| * |
| * @since 3.3 |
| */ |
| private boolean fIgnoreEvents= false; |
| |
| /** |
| * Creates a new selection provider. |
| * |
| * @param painter the painter that the created provider interacts with |
| */ |
| RevisionSelectionProvider(RevisionPainter painter) { |
| fPainter= painter; |
| } |
| |
| @Override |
| public void addSelectionChangedListener(ISelectionChangedListener listener) { |
| fListeners.add(listener); |
| } |
| |
| @Override |
| public void removeSelectionChangedListener(ISelectionChangedListener listener) { |
| fListeners.remove(listener); |
| } |
| |
| @Override |
| public ISelection getSelection() { |
| if (fSelection == null) |
| return StructuredSelection.EMPTY; |
| return new StructuredSelection(fSelection); |
| } |
| |
| @Override |
| public void setSelection(ISelection selection) { |
| if (fIgnoreEvents) |
| return; |
| if (selection instanceof IStructuredSelection) { |
| Object first= ((IStructuredSelection) selection).getFirstElement(); |
| if (first instanceof Revision) |
| fPainter.handleRevisionSelected((Revision) first); |
| else if (first instanceof String) |
| fPainter.handleRevisionSelected((String) first); |
| else if (selection.isEmpty()) |
| fPainter.handleRevisionSelected((Revision) null); |
| } |
| } |
| |
| /** |
| * Installs the selection provider on the viewer. |
| * |
| * @param viewer the viewer on which we listen to for post selection events |
| */ |
| void install(ITextViewer viewer) { |
| uninstall(); |
| fViewer= viewer; |
| if (fViewer != null) { |
| ISelectionProvider provider= fViewer.getSelectionProvider(); |
| if (provider instanceof IPostSelectionProvider) { |
| IPostSelectionProvider postProvider= (IPostSelectionProvider) provider; |
| fSelectionListener= new PostSelectionListener(postProvider); |
| } |
| } |
| } |
| |
| /** |
| * Uninstalls the selection provider. |
| */ |
| void uninstall() { |
| fViewer= null; |
| if (fSelectionListener != null) { |
| fSelectionListener.dispose(); |
| fSelectionListener= null; |
| } |
| } |
| |
| /** |
| * Private protocol used by {@link RevisionPainter} to signal selection of a revision. |
| * |
| * @param revision the selected revision, or <code>null</code> for none |
| */ |
| void revisionSelected(Revision revision) { |
| setSelectedRevision(revision); |
| } |
| |
| /** |
| * Updates the currently selected revision and sends out an event if it changed. |
| * |
| * @param revision the newly selected revision or <code>null</code> for none |
| */ |
| private void setSelectedRevision(Revision revision) { |
| if (revision != fSelection) { |
| fSelection= revision; |
| fireSelectionEvent(); |
| } |
| } |
| |
| private void fireSelectionEvent() { |
| fIgnoreEvents= true; |
| try { |
| ISelection selection= getSelection(); |
| SelectionChangedEvent event= new SelectionChangedEvent(this, selection); |
| |
| for (ISelectionChangedListener listener : fListeners) { |
| listener.selectionChanged(event); |
| } |
| } finally { |
| fIgnoreEvents= false; |
| } |
| } |
| } |