279fc491853d63ac2c547c2ecad2c1bb711b9ad8
[phpeclipse.git] / net.sourceforge.phpeclipse.ui / src / net / sourceforge / phpdt / internal / ui / viewsupport / SelectionListenerWithASTManager.java
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
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.ui.viewsupport;
12
13 import java.util.HashMap;
14 import java.util.Map;
15
16 import org.eclipse.core.runtime.IProgressMonitor;
17 import org.eclipse.core.runtime.IStatus;
18 import org.eclipse.core.runtime.NullProgressMonitor;
19 import org.eclipse.core.runtime.OperationCanceledException;
20 import org.eclipse.core.runtime.Status;
21 import org.eclipse.core.runtime.jobs.Job;
22 import org.eclipse.jface.text.ITextSelection;
23 //incastrix
24 //import org.eclipse.jface.util.ListenerList;
25 import org.eclipse.core.runtime.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.texteditor.ITextEditor;
32
33 /**
34  * Infrastructure to share an AST for editor post selection listeners.
35  */
36 public class SelectionListenerWithASTManager {
37
38         private static SelectionListenerWithASTManager fgDefault;
39
40         /**
41          * @return Returns the default manager instance.
42          */
43         public static SelectionListenerWithASTManager getDefault() {
44                 if (fgDefault == null) {
45                         fgDefault = new SelectionListenerWithASTManager();
46                 }
47                 return fgDefault;
48         }
49
50         private final static class PartListenerGroup {
51                 private ITextEditor fPart;
52
53                 private ISelectionChangedListener fSelectionListener,
54                                 fPostSelectionListener;
55
56                 private Job fCurrentJob;
57
58                 private ListenerList fAstListeners;
59
60                 /**
61                  * Lock to avoid having more than one calculateAndInform job in
62                  * parallel. Only jobs may synchronize on this as otherwise deadlocks
63                  * are possible.
64                  */
65                 private final Object fJobLock = new Object();
66
67                 public PartListenerGroup(ITextEditor part) {
68                         fPart = part;
69                         fCurrentJob = null;
70                         fAstListeners = new ListenerList();
71
72                         fSelectionListener = new ISelectionChangedListener() {
73                                 public void selectionChanged(SelectionChangedEvent event) {
74                                         ISelection selection = event.getSelection();
75                                         if (selection instanceof ITextSelection) {
76                                                 fireSelectionChanged((ITextSelection) selection);
77                                         }
78                                 }
79                         };
80
81                         fPostSelectionListener = new ISelectionChangedListener() {
82                                 public void selectionChanged(SelectionChangedEvent event) {
83                                         ISelection selection = event.getSelection();
84                                         if (selection instanceof ITextSelection) {
85                                                 firePostSelectionChanged((ITextSelection) selection);
86                                         }
87                                 }
88                         };
89                 }
90
91                 public boolean isEmpty() {
92                         return fAstListeners.isEmpty();
93                 }
94
95                 public void install(ISelectionListenerWithAST listener) {
96                         if (isEmpty()) {
97                                 ISelectionProvider selectionProvider = fPart
98                                                 .getSelectionProvider();
99                                 if (selectionProvider instanceof IPostSelectionProvider) {
100                                         ((IPostSelectionProvider) selectionProvider)
101                                                         .addPostSelectionChangedListener(fPostSelectionListener);
102                                         selectionProvider
103                                                         .addSelectionChangedListener(fSelectionListener);
104                                 }
105                         }
106                         fAstListeners.add(listener);
107                 }
108
109                 public void uninstall(ISelectionListenerWithAST listener) {
110                         fAstListeners.remove(listener);
111                         if (isEmpty()) {
112                                 ISelectionProvider selectionProvider = fPart
113                                                 .getSelectionProvider();
114                                 if (selectionProvider instanceof IPostSelectionProvider) {
115                                         ((IPostSelectionProvider) selectionProvider)
116                                                         .removePostSelectionChangedListener(fPostSelectionListener);
117                                         selectionProvider
118                                                         .removeSelectionChangedListener(fSelectionListener);
119                                 }
120                         }
121                 }
122
123                 public void fireSelectionChanged(final ITextSelection selection) {
124                         if (fCurrentJob != null) {
125                                 fCurrentJob.cancel();
126                         }
127                 }
128
129                 public void firePostSelectionChanged(final ITextSelection selection) {
130                         if (fCurrentJob != null) {
131                                 fCurrentJob.cancel();
132                         }
133
134                         fCurrentJob = new Job("SelectionListenerWithASTManager Job") {// JavaUIMessages.SelectionListenerWithASTManager_job_title)
135                                                                                                                                                         // {
136                                 public IStatus run(IProgressMonitor monitor) {
137                                         if (monitor == null) {
138                                                 monitor = new NullProgressMonitor();
139                                         }
140                                         synchronized (fJobLock) {
141                                                 return calculateASTandInform(/*input,*/ selection, monitor);
142                                         }
143                                 }
144                         };
145                         fCurrentJob.setPriority(Job.DECORATE);
146                         fCurrentJob.setSystem(true);
147                         fCurrentJob.schedule();
148                 }
149
150                 protected IStatus calculateASTandInform(/*IJavaElement input,*/
151                                 ITextSelection selection, IProgressMonitor monitor) {
152                         if (monitor.isCanceled()) {
153                                 return Status.CANCEL_STATUS;
154                         }
155                         // create AST
156                         try {
157                                 // CompilationUnit astRoot=
158                                 // PHPeclipsePlugin.getDefault().getASTProvider().getAST(input,
159                                 // ASTProvider.WAIT_ACTIVE_ONLY, monitor);
160
161                                 // if (astRoot != null && !monitor.isCanceled()) {
162                                 Object[] listeners;
163                                 synchronized (PartListenerGroup.this) {
164                                         listeners = fAstListeners.getListeners();
165                                 }
166                                 for (int i = 0; i < listeners.length; i++) {
167                                         ((ISelectionListenerWithAST) listeners[i])
168                                                         .selectionChanged(fPart, selection);// , astRoot);
169                                         if (monitor.isCanceled()) {
170                                                 return Status.CANCEL_STATUS;
171                                         }
172                                 }
173                                 return Status.OK_STATUS;
174                                 // }
175                         } catch (OperationCanceledException e) {
176                                 // thrown when cancelling the AST creation
177                         }
178                         return Status.CANCEL_STATUS;
179                 }
180         }
181
182         private Map fListenerGroups;
183
184         private SelectionListenerWithASTManager() {
185                 fListenerGroups = new HashMap();
186         }
187
188         /**
189          * Registers a selection listener for the given editor part.
190          * 
191          * @param part
192          *            The editor part to listen to.
193          * @param listener
194          *            The listener to register.
195          */
196         public void addListener(ITextEditor part, ISelectionListenerWithAST listener) {
197                 synchronized (this) {
198                         PartListenerGroup partListener = (PartListenerGroup) fListenerGroups
199                                         .get(part);
200                         if (partListener == null) {
201                                 partListener = new PartListenerGroup(part);
202                                 fListenerGroups.put(part, partListener);
203                         }
204                         partListener.install(listener);
205                 }
206         }
207
208         /**
209          * Unregisters a selection listener.
210          * 
211          * @param part
212          *            The editor part the listener was registered.
213          * @param listener
214          *            The listener to unregister.
215          */
216         public void removeListener(ITextEditor part,
217                         ISelectionListenerWithAST listener) {
218                 synchronized (this) {
219                         PartListenerGroup partListener = (PartListenerGroup) fListenerGroups
220                                         .get(part);
221                         if (partListener != null) {
222                                 partListener.uninstall(listener);
223                                 if (partListener.isEmpty()) {
224                                         fListenerGroups.remove(part);
225                                 }
226                         }
227                 }
228         }
229
230         /**
231          * Forces a selection changed event that is sent to all listeners registered
232          * to the given editor part. The event is sent from a background thread:
233          * this method call can return before the listeners are informed.
234          * 
235          * @param part
236          *            The editor part that has a changed selection
237          * @param selection
238          *            The new text selection
239          */
240         public void forceSelectionChange(ITextEditor part, ITextSelection selection) {
241                 synchronized (this) {
242                         PartListenerGroup partListener = (PartListenerGroup) fListenerGroups
243                                         .get(part);
244                         if (partListener != null) {
245                                 partListener.firePostSelectionChanged(selection);
246                         }
247                 }
248         }
249 }