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();
51 private final static class PartListenerGroup {
52 private ITextEditor fPart;
54 private ISelectionChangedListener fSelectionListener,
55 fPostSelectionListener;
57 private Job fCurrentJob;
59 private ListenerList fAstListeners;
62 * Lock to avoid having more than one calculateAndInform job in
63 * parallel. Only jobs may synchronize on this as otherwise deadlocks
66 private final Object fJobLock = new Object();
68 public PartListenerGroup(ITextEditor part) {
71 fAstListeners = new ListenerList();
73 fSelectionListener = new ISelectionChangedListener() {
74 public void selectionChanged(SelectionChangedEvent event) {
75 ISelection selection = event.getSelection();
76 if (selection instanceof ITextSelection) {
77 fireSelectionChanged((ITextSelection) selection);
82 fPostSelectionListener = new ISelectionChangedListener() {
83 public void selectionChanged(SelectionChangedEvent event) {
84 ISelection selection = event.getSelection();
85 if (selection instanceof ITextSelection) {
86 firePostSelectionChanged((ITextSelection) selection);
92 public boolean isEmpty() {
93 return fAstListeners.isEmpty();
96 public void install(ISelectionListenerWithAST listener) {
98 ISelectionProvider selectionProvider = fPart
99 .getSelectionProvider();
100 if (selectionProvider instanceof IPostSelectionProvider) {
101 ((IPostSelectionProvider) selectionProvider)
102 .addPostSelectionChangedListener(fPostSelectionListener);
104 .addSelectionChangedListener(fSelectionListener);
107 fAstListeners.add(listener);
110 public void uninstall(ISelectionListenerWithAST listener) {
111 fAstListeners.remove(listener);
113 ISelectionProvider selectionProvider = fPart
114 .getSelectionProvider();
115 if (selectionProvider instanceof IPostSelectionProvider) {
116 ((IPostSelectionProvider) selectionProvider)
117 .removePostSelectionChangedListener(fPostSelectionListener);
119 .removeSelectionChangedListener(fSelectionListener);
124 public void fireSelectionChanged(final ITextSelection selection) {
125 if (fCurrentJob != null) {
126 fCurrentJob.cancel();
130 public void firePostSelectionChanged(final ITextSelection selection) {
131 if (fCurrentJob != null) {
132 fCurrentJob.cancel();
134 final IJavaElement input = getJavaElement();
139 fCurrentJob = new Job("SelectionListenerWithASTManager Job") {// JavaUIMessages.SelectionListenerWithASTManager_job_title)
141 public IStatus run(IProgressMonitor monitor) {
142 if (monitor == null) {
143 monitor = new NullProgressMonitor();
145 synchronized (fJobLock) {
146 return calculateASTandInform(input, selection, monitor);
150 fCurrentJob.setPriority(Job.DECORATE);
151 fCurrentJob.setSystem(true);
152 fCurrentJob.schedule();
155 private IJavaElement getJavaElement() {
156 IEditorInput editorInput = fPart.getEditorInput();
157 if (editorInput != null)
158 return (IJavaElement) editorInput
159 .getAdapter(IJavaElement.class);
164 protected IStatus calculateASTandInform(IJavaElement input,
165 ITextSelection selection, IProgressMonitor monitor) {
166 if (monitor.isCanceled()) {
167 return Status.CANCEL_STATUS;
171 // CompilationUnit astRoot=
172 // PHPeclipsePlugin.getDefault().getASTProvider().getAST(input,
173 // ASTProvider.WAIT_ACTIVE_ONLY, monitor);
175 // if (astRoot != null && !monitor.isCanceled()) {
177 synchronized (PartListenerGroup.this) {
178 listeners = fAstListeners.getListeners();
180 for (int i = 0; i < listeners.length; i++) {
181 ((ISelectionListenerWithAST) listeners[i])
182 .selectionChanged(fPart, selection);// , astRoot);
183 if (monitor.isCanceled()) {
184 return Status.CANCEL_STATUS;
187 return Status.OK_STATUS;
189 } catch (OperationCanceledException e) {
190 // thrown when cancelling the AST creation
192 return Status.CANCEL_STATUS;
196 private Map fListenerGroups;
198 private SelectionListenerWithASTManager() {
199 fListenerGroups = new HashMap();
203 * Registers a selection listener for the given editor part.
206 * The editor part to listen to.
208 * The listener to register.
210 public void addListener(ITextEditor part, ISelectionListenerWithAST listener) {
211 synchronized (this) {
212 PartListenerGroup partListener = (PartListenerGroup) fListenerGroups
214 if (partListener == null) {
215 partListener = new PartListenerGroup(part);
216 fListenerGroups.put(part, partListener);
218 partListener.install(listener);
223 * Unregisters a selection listener.
226 * The editor part the listener was registered.
228 * The listener to unregister.
230 public void removeListener(ITextEditor part,
231 ISelectionListenerWithAST listener) {
232 synchronized (this) {
233 PartListenerGroup partListener = (PartListenerGroup) fListenerGroups
235 if (partListener != null) {
236 partListener.uninstall(listener);
237 if (partListener.isEmpty()) {
238 fListenerGroups.remove(part);
245 * Forces a selection changed event that is sent to all listeners registered
246 * to the given editor part. The event is sent from a background thread:
247 * this method call can return before the listeners are informed.
250 * The editor part that has a changed selection
252 * The new text selection
254 public void forceSelectionChange(ITextEditor part, ITextSelection selection) {
255 synchronized (this) {
256 PartListenerGroup partListener = (PartListenerGroup) fListenerGroups
258 if (partListener != null) {
259 partListener.firePostSelectionChanged(selection);