001: /*******************************************************************************
002: * Copyright (c) 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jface.internal.text.revisions;
011:
012: import org.eclipse.core.runtime.ListenerList;
013:
014: import org.eclipse.jface.text.ITextSelection;
015: import org.eclipse.jface.text.ITextViewer;
016: import org.eclipse.jface.text.revisions.Revision;
017:
018: import org.eclipse.jface.viewers.IPostSelectionProvider;
019: import org.eclipse.jface.viewers.ISelection;
020: import org.eclipse.jface.viewers.ISelectionChangedListener;
021: import org.eclipse.jface.viewers.ISelectionProvider;
022: import org.eclipse.jface.viewers.IStructuredSelection;
023: import org.eclipse.jface.viewers.SelectionChangedEvent;
024: import org.eclipse.jface.viewers.StructuredSelection;
025:
026: /**
027: * A selection provider for annotate revisions. Selections of a revision can currently happen in
028: * following ways - note that this list may be changed in the future:
029: * <ul>
030: * <li>when the user clicks the revision ruler with the mouse</li>
031: * <li>when the caret is moved to a revision's line (only on post-selection)</li>
032: * </ul>
033: * <p>
034: * Calling {@link #setSelection(ISelection)} will set the current sticky revision on the ruler.
035: * </p>
036: *
037: * @since 3.2
038: */
039: public final class RevisionSelectionProvider implements
040: ISelectionProvider {
041:
042: /**
043: * Post selection listener on the viewer that remembers the selection provider it is registered
044: * with.
045: */
046: private final class PostSelectionListener implements
047: ISelectionChangedListener {
048: private final IPostSelectionProvider fPostProvider;
049:
050: public PostSelectionListener(IPostSelectionProvider postProvider) {
051: postProvider.addPostSelectionChangedListener(this );
052: fPostProvider = postProvider;
053: }
054:
055: public void selectionChanged(SelectionChangedEvent event) {
056: ISelection selection = event.getSelection();
057: if (selection instanceof ITextSelection) {
058: ITextSelection ts = (ITextSelection) selection;
059: int offset = ts.getOffset();
060: setSelectedRevision(fPainter.getRevision(offset));
061: }
062:
063: }
064:
065: public void dispose() {
066: fPostProvider.removePostSelectionChangedListener(this );
067: }
068: }
069:
070: private final RevisionPainter fPainter;
071: private final ListenerList fListeners = new ListenerList();
072:
073: /**
074: * The text viewer once we are installed, <code>null</code> if not installed.
075: */
076: private ITextViewer fViewer;
077: /**
078: * The selection listener on the viewer, or <code>null</code>.
079: */
080: private PostSelectionListener fSelectionListener;
081: /**
082: * The last selection, or <code>null</code>.
083: */
084: private Revision fSelection;
085: /**
086: * Incoming selection changes are ignored while sending out events.
087: *
088: * @since 3.3
089: */
090: private boolean fIgnoreEvents = false;
091:
092: /**
093: * Creates a new selection provider.
094: *
095: * @param painter the painter that the created provider interacts with
096: */
097: RevisionSelectionProvider(RevisionPainter painter) {
098: fPainter = painter;
099: }
100:
101: /*
102: * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
103: */
104: public void addSelectionChangedListener(
105: ISelectionChangedListener listener) {
106: fListeners.add(listener);
107: }
108:
109: /*
110: * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
111: */
112: public void removeSelectionChangedListener(
113: ISelectionChangedListener listener) {
114: fListeners.remove(listener);
115: }
116:
117: /*
118: * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection()
119: */
120: public ISelection getSelection() {
121: if (fSelection == null)
122: return StructuredSelection.EMPTY;
123: return new StructuredSelection(fSelection);
124: }
125:
126: /*
127: * @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(org.eclipse.jface.viewers.ISelection)
128: */
129: public void setSelection(ISelection selection) {
130: if (fIgnoreEvents)
131: return;
132: if (selection instanceof IStructuredSelection) {
133: Object first = ((IStructuredSelection) selection)
134: .getFirstElement();
135: if (first instanceof Revision)
136: fPainter.handleRevisionSelected((Revision) first);
137: else if (first instanceof String)
138: fPainter.handleRevisionSelected((String) first);
139: else if (selection.isEmpty())
140: fPainter.handleRevisionSelected((Revision) null);
141: }
142: }
143:
144: /**
145: * Installs the selection provider on the viewer.
146: *
147: * @param viewer the viewer on which we listen to for post selection events
148: */
149: void install(ITextViewer viewer) {
150: uninstall();
151: fViewer = viewer;
152: if (fViewer != null) {
153: ISelectionProvider provider = fViewer
154: .getSelectionProvider();
155: if (provider instanceof IPostSelectionProvider) {
156: IPostSelectionProvider postProvider = (IPostSelectionProvider) provider;
157: fSelectionListener = new PostSelectionListener(
158: postProvider);
159: }
160: }
161: }
162:
163: /**
164: * Uninstalls the selection provider.
165: */
166: void uninstall() {
167: fViewer = null;
168: if (fSelectionListener != null) {
169: fSelectionListener.dispose();
170: fSelectionListener = null;
171: }
172: }
173:
174: /**
175: * Private protocol used by {@link RevisionPainter} to signal selection of a revision.
176: *
177: * @param revision the selected revision, or <code>null</code> for none
178: */
179: void revisionSelected(Revision revision) {
180: setSelectedRevision(revision);
181: }
182:
183: /**
184: * Updates the currently selected revision and sends out an event if it changed.
185: *
186: * @param revision the newly selected revision or <code>null</code> for none
187: */
188: private void setSelectedRevision(Revision revision) {
189: if (revision != fSelection) {
190: fSelection = revision;
191: fireSelectionEvent();
192: }
193: }
194:
195: private void fireSelectionEvent() {
196: fIgnoreEvents = true;
197: try {
198: ISelection selection = getSelection();
199: SelectionChangedEvent event = new SelectionChangedEvent(
200: this , selection);
201:
202: Object[] listeners = fListeners.getListeners();
203: for (int i = 0; i < listeners.length; i++)
204: ((ISelectionChangedListener) listeners[i])
205: .selectionChanged(event);
206: } finally {
207: fIgnoreEvents = false;
208: }
209: }
210: }
|