1 /*******************************************************************************
2 * Copyright (c) 2000, 2005 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.ui.viewsupport;
13 import java.util.HashMap;
16 import net.sourceforge.phpdt.core.IJavaElement;
18 import org.eclipse.core.runtime.IProgressMonitor;
19 import org.eclipse.core.runtime.IStatus;
20 import org.eclipse.core.runtime.NullProgressMonitor;
21 import org.eclipse.core.runtime.OperationCanceledException;
22 import org.eclipse.core.runtime.Status;
23 import org.eclipse.core.runtime.jobs.Job;
24 import org.eclipse.jface.text.ITextSelection;
25 import org.eclipse.jface.util.ListenerList;
26 import org.eclipse.jface.viewers.IPostSelectionProvider;
27 import org.eclipse.jface.viewers.ISelection;
28 import org.eclipse.jface.viewers.ISelectionChangedListener;
29 import org.eclipse.jface.viewers.ISelectionProvider;
30 import org.eclipse.jface.viewers.SelectionChangedEvent;
31 import org.eclipse.ui.IEditorInput;
32 import org.eclipse.ui.texteditor.ITextEditor;
35 * Infrastructure to share an AST for editor post selection listeners.
37 public class SelectionListenerWithASTManager {
39 private static SelectionListenerWithASTManager fgDefault;
42 * @return Returns the default manager instance.
44 public static SelectionListenerWithASTManager getDefault() {
45 if (fgDefault == null) {
46 fgDefault= new SelectionListenerWithASTManager();
52 private final static class PartListenerGroup {
53 private ITextEditor fPart;
54 private ISelectionChangedListener fSelectionListener, fPostSelectionListener;
55 private Job fCurrentJob;
56 private ListenerList fAstListeners;
58 * Lock to avoid having more than one calculateAndInform job in parallel.
59 * Only jobs may synchronize on this as otherwise deadlocks are possible.
61 private final Object fJobLock= new Object();
63 public PartListenerGroup(ITextEditor part) {
66 fAstListeners= new ListenerList();
68 fSelectionListener= new ISelectionChangedListener() {
69 public void selectionChanged(SelectionChangedEvent event) {
70 ISelection selection= event.getSelection();
71 if (selection instanceof ITextSelection) {
72 fireSelectionChanged((ITextSelection) selection);
77 fPostSelectionListener= new ISelectionChangedListener() {
78 public void selectionChanged(SelectionChangedEvent event) {
79 ISelection selection= event.getSelection();
80 if (selection instanceof ITextSelection) {
81 firePostSelectionChanged((ITextSelection) selection);
87 public boolean isEmpty() {
88 return fAstListeners.isEmpty();
91 public void install(ISelectionListenerWithAST listener) {
93 ISelectionProvider selectionProvider= fPart.getSelectionProvider();
94 if (selectionProvider instanceof IPostSelectionProvider) {
95 ((IPostSelectionProvider) selectionProvider).addPostSelectionChangedListener(fPostSelectionListener);
96 selectionProvider.addSelectionChangedListener(fSelectionListener);
99 fAstListeners.add(listener);
102 public void uninstall(ISelectionListenerWithAST listener) {
103 fAstListeners.remove(listener);
105 ISelectionProvider selectionProvider= fPart.getSelectionProvider();
106 if (selectionProvider instanceof IPostSelectionProvider) {
107 ((IPostSelectionProvider) selectionProvider).removePostSelectionChangedListener(fPostSelectionListener);
108 selectionProvider.removeSelectionChangedListener(fSelectionListener);
113 public void fireSelectionChanged(final ITextSelection selection) {
114 if (fCurrentJob != null) {
115 fCurrentJob.cancel();
119 public void firePostSelectionChanged(final ITextSelection selection) {
120 if (fCurrentJob != null) {
121 fCurrentJob.cancel();
123 final IJavaElement input= getJavaElement();
128 fCurrentJob= new Job("SelectionListenerWithASTManager Job") {//JavaUIMessages.SelectionListenerWithASTManager_job_title) {
129 public IStatus run(IProgressMonitor monitor) {
130 if (monitor == null) {
131 monitor= new NullProgressMonitor();
133 synchronized (fJobLock) {
134 return calculateASTandInform(input, selection, monitor);
138 fCurrentJob.setPriority(Job.DECORATE);
139 fCurrentJob.setSystem(true);
140 fCurrentJob.schedule();
143 private IJavaElement getJavaElement() {
144 IEditorInput editorInput= fPart.getEditorInput();
145 if (editorInput != null)
146 return (IJavaElement)editorInput.getAdapter(IJavaElement.class);
151 protected IStatus calculateASTandInform(IJavaElement input, ITextSelection selection, IProgressMonitor monitor) {
152 if (monitor.isCanceled()) {
153 return Status.CANCEL_STATUS;
157 // CompilationUnit astRoot= PHPeclipsePlugin.getDefault().getASTProvider().getAST(input, ASTProvider.WAIT_ACTIVE_ONLY, monitor);
159 // if (astRoot != null && !monitor.isCanceled()) {
161 synchronized (PartListenerGroup.this) {
162 listeners= fAstListeners.getListeners();
164 for (int i= 0; i < listeners.length; i++) {
165 ((ISelectionListenerWithAST) listeners[i]).selectionChanged(fPart, selection);//, astRoot);
166 if (monitor.isCanceled()) {
167 return Status.CANCEL_STATUS;
170 return Status.OK_STATUS;
172 } catch (OperationCanceledException e) {
173 // thrown when cancelling the AST creation
175 return Status.CANCEL_STATUS;
180 private Map fListenerGroups;
182 private SelectionListenerWithASTManager() {
183 fListenerGroups= new HashMap();
187 * Registers a selection listener for the given editor part.
188 * @param part The editor part to listen to.
189 * @param listener The listener to register.
191 public void addListener(ITextEditor part, ISelectionListenerWithAST listener) {
192 synchronized (this) {
193 PartListenerGroup partListener= (PartListenerGroup) fListenerGroups.get(part);
194 if (partListener == null) {
195 partListener= new PartListenerGroup(part);
196 fListenerGroups.put(part, partListener);
198 partListener.install(listener);
203 * Unregisters a selection listener.
204 * @param part The editor part the listener was registered.
205 * @param listener The listener to unregister.
207 public void removeListener(ITextEditor part, ISelectionListenerWithAST listener) {
208 synchronized (this) {
209 PartListenerGroup partListener= (PartListenerGroup) fListenerGroups.get(part);
210 if (partListener != null) {
211 partListener.uninstall(listener);
212 if (partListener.isEmpty()) {
213 fListenerGroups.remove(part);
220 * Forces a selection changed event that is sent to all listeners registered to the given editor
221 * part. The event is sent from a background thread: this method call can return before the listeners
223 * @param part The editor part that has a changed selection
224 * @param selection The new text selection
226 public void forceSelectionChange(ITextEditor part, ITextSelection selection) {
227 synchronized (this) {
228 PartListenerGroup partListener= (PartListenerGroup) fListenerGroups.get(part);
229 if (partListener != null) {
230 partListener.firePostSelectionChanged(selection);