new version with WorkingCopy Management
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / JavaOutlinePage.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpeclipse.phpeditor;
12
13
14 import java.util.Enumeration;
15 import java.util.Hashtable;
16 import java.util.List;
17 import java.util.Vector;
18
19 import net.sourceforge.phpdt.core.ElementChangedEvent;
20 import net.sourceforge.phpdt.core.ICompilationUnit;
21 import net.sourceforge.phpdt.core.IElementChangedListener;
22 import net.sourceforge.phpdt.core.IJavaElement;
23 import net.sourceforge.phpdt.core.IJavaElementDelta;
24 import net.sourceforge.phpdt.core.IMember;
25 import net.sourceforge.phpdt.core.IMethod;
26 import net.sourceforge.phpdt.core.IParent;
27 import net.sourceforge.phpdt.core.ISourceRange;
28 import net.sourceforge.phpdt.core.ISourceReference;
29 import net.sourceforge.phpdt.core.IType;
30 import net.sourceforge.phpdt.core.JavaModelException;
31 import net.sourceforge.phpdt.internal.ui.PHPUiImages;
32 import net.sourceforge.phpdt.internal.ui.actions.CompositeActionGroup;
33 import net.sourceforge.phpdt.internal.ui.packageview.SelectionTransferDragAdapter;
34 import net.sourceforge.phpdt.internal.ui.viewsupport.AppearanceAwareLabelProvider;
35 import net.sourceforge.phpdt.internal.ui.viewsupport.DecoratingJavaLabelProvider;
36 import net.sourceforge.phpdt.internal.ui.viewsupport.JavaElementLabels;
37 import net.sourceforge.phpdt.internal.ui.viewsupport.StatusBarUpdater;
38 import net.sourceforge.phpdt.ui.JavaElementSorter;
39 import net.sourceforge.phpdt.ui.JavaUI;
40 import net.sourceforge.phpdt.ui.PreferenceConstants;
41 import net.sourceforge.phpdt.ui.ProblemsLabelDecorator.ProblemsLabelChangedEvent;
42 import net.sourceforge.phpdt.ui.actions.GenerateActionGroup;
43 import net.sourceforge.phpdt.ui.actions.MemberFilterActionGroup;
44 import net.sourceforge.phpeclipse.PHPCore;
45 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
46
47 import org.eclipse.core.resources.IResource;
48 import org.eclipse.core.runtime.IAdaptable;
49 import net.sourceforge.phpdt.internal.ui.dnd.JdtViewerDragAdapter;
50 import net.sourceforge.phpdt.internal.ui.dnd.TransferDragSourceListener;
51 import org.eclipse.jface.action.Action;
52 import org.eclipse.jface.action.IAction;
53 import org.eclipse.jface.action.IMenuListener;
54 import org.eclipse.jface.action.IMenuManager;
55 import org.eclipse.jface.action.IStatusLineManager;
56 import org.eclipse.jface.action.IToolBarManager;
57 import org.eclipse.jface.action.MenuManager;
58 import org.eclipse.jface.preference.IPreferenceStore;
59 import org.eclipse.jface.text.Assert;
60 import org.eclipse.jface.text.ITextSelection;
61 import org.eclipse.jface.util.IPropertyChangeListener;
62 import org.eclipse.jface.util.ListenerList;
63 import org.eclipse.jface.util.PropertyChangeEvent;
64 import org.eclipse.jface.viewers.IBaseLabelProvider;
65 import org.eclipse.jface.viewers.ISelection;
66 import org.eclipse.jface.viewers.ISelectionChangedListener;
67 import org.eclipse.jface.viewers.IStructuredSelection;
68 import org.eclipse.jface.viewers.ITreeContentProvider;
69 import org.eclipse.jface.viewers.LabelProviderChangedEvent;
70 import org.eclipse.jface.viewers.StructuredSelection;
71 import org.eclipse.jface.viewers.TreeViewer;
72 import org.eclipse.jface.viewers.Viewer;
73 import org.eclipse.jface.viewers.ViewerFilter;
74 import org.eclipse.swt.SWT;
75 import org.eclipse.swt.custom.BusyIndicator;
76 import org.eclipse.swt.dnd.DND;
77 import org.eclipse.swt.dnd.Transfer;
78 import org.eclipse.swt.events.KeyAdapter;
79 import org.eclipse.swt.events.KeyEvent;
80 import org.eclipse.swt.widgets.Composite;
81 import org.eclipse.swt.widgets.Control;
82 import org.eclipse.swt.widgets.Display;
83 import org.eclipse.swt.widgets.Item;
84 import org.eclipse.swt.widgets.Menu;
85 import org.eclipse.swt.widgets.Tree;
86 import org.eclipse.swt.widgets.Widget;
87 import org.eclipse.ui.IActionBars;
88 import org.eclipse.ui.actions.ActionContext;
89 import org.eclipse.ui.actions.ActionGroup;
90 import org.eclipse.ui.internal.model.WorkbenchAdapter;
91 import org.eclipse.ui.model.IWorkbenchAdapter;
92 import org.eclipse.ui.part.IPageSite;
93 import org.eclipse.ui.part.IShowInSource;
94 import org.eclipse.ui.part.IShowInTarget;
95 import org.eclipse.ui.part.IShowInTargetList;
96 import org.eclipse.ui.part.Page;
97 import org.eclipse.ui.part.ShowInContext;
98 import org.eclipse.ui.texteditor.ITextEditorActionConstants;
99 import org.eclipse.ui.texteditor.IUpdate;
100 import org.eclipse.ui.texteditor.TextEditorAction;
101 import org.eclipse.ui.texteditor.TextOperationAction;
102 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
103 import org.eclipse.ui.views.navigator.LocalSelectionTransfer;
104
105
106
107
108
109 /**
110  * The content outline page of the Java editor. The viewer implements a proprietary
111  * update mechanism based on Java model deltas. It does not react on domain changes.
112  * It is specified to show the content of ICompilationUnits and IClassFiles.
113  * Pulishes its context menu under <code>JavaPlugin.getDefault().getPluginId() + ".outline"</code>.
114  */
115 public class JavaOutlinePage extends Page implements IContentOutlinePage, IAdaptable {
116
117                         static Object[] NO_CHILDREN= new Object[0];
118    
119                         /**
120                          * The element change listener of the java outline viewer.
121                          * @see IElementChangedListener
122                          */
123                         class ElementChangedListener implements IElementChangedListener {
124                                 
125                                 public void elementChanged(final ElementChangedEvent e) {
126                                         
127                                         if (getControl() == null)
128                                                 return;
129                                                 
130                                         Display d= getControl().getDisplay();
131                                         if (d != null) {
132                                                 d.asyncExec(new Runnable() {
133                                                         public void run() {
134                                                                 ICompilationUnit cu= (ICompilationUnit) fInput;
135                                                                 IJavaElement base= cu;
136                                                                 if (fTopLevelTypeOnly) {
137                                                                         base= getMainType(cu);
138                                                                         if (base == null) {
139                                                                                 if (fOutlineViewer != null)
140                                                                                         fOutlineViewer.refresh(true);
141                                                                                 return;
142                                                                         }
143                                                                 }
144                                                                 IJavaElementDelta delta= findElement(base, e.getDelta());
145                                                                 if (delta != null && fOutlineViewer != null) {
146                                                                         fOutlineViewer.reconcile(delta);
147                                                                 }
148                                                         }
149                                                 });
150                                         }
151                                 }
152                                 
153                                 protected IJavaElementDelta findElement(IJavaElement unit, IJavaElementDelta delta) {
154                                         
155                                         if (delta == null || unit == null)
156                                                 return null;
157                                         
158                                         IJavaElement element= delta.getElement();
159                                         
160                                         if (unit.equals(element))
161                                                 return delta;
162                                         
163                                         if (element.getElementType() > IJavaElement.CLASS_FILE)
164                                                 return null;
165                                                 
166                                         IJavaElementDelta[] children= delta.getAffectedChildren();
167                                         if (children == null || children.length == 0)
168                                                 return null;
169                                                 
170                                         for (int i= 0; i < children.length; i++) {
171                                                 IJavaElementDelta d= findElement(unit, children[i]);
172                                                 if (d != null)
173                                                         return d;
174                                         }
175                                         
176                                         return null;
177                                 }
178                         };
179          
180                         static class NoClassElement extends WorkbenchAdapter implements IAdaptable {
181                                 /*
182                                  * @see java.lang.Object#toString()
183                                  */
184                                 public String toString() {
185                                         return PHPEditorMessages.getString("JavaOutlinePage.error.NoTopLevelType"); //$NON-NLS-1$
186                                 }
187                 
188                                 /*
189                                  * @see org.eclipse.core.runtime.IAdaptable#getAdapter(Class)
190                                  */
191                                 public Object getAdapter(Class clas) {
192                                         if (clas == IWorkbenchAdapter.class)
193                                                 return this;
194                                         return null;
195                                 }
196                         }
197                         
198                         /**
199                          * Content provider for the children of an ICompilationUnit or
200                          * an IClassFile
201                          * @see ITreeContentProvider
202                          */
203                         class ChildrenProvider implements ITreeContentProvider {
204             
205                                 private Object[] NO_CLASS= new Object[] {new NoClassElement()};
206                                 private ElementChangedListener fListener;
207                                 
208                                 protected boolean matches(IJavaElement element) {
209                                         if (element.getElementType() == IJavaElement.METHOD) {
210                                                 String name= element.getElementName();
211                                                 return (name != null && name.indexOf('<') >= 0);
212                                         }
213                                         return false;
214                                 }
215                                 
216                                 protected IJavaElement[] filter(IJavaElement[] children) {
217                                         boolean initializers= false;
218                                         for (int i= 0; i < children.length; i++) {
219                                                 if (matches(children[i])) {
220                                                         initializers= true;
221                                                         break;
222                                                 }
223                                         }
224                                                         
225                                         if (!initializers)
226                                                 return children;
227                                                 
228                                         Vector v= new Vector();
229                                         for (int i= 0; i < children.length; i++) {
230                                                 if (matches(children[i]))
231                                                         continue;
232                                                 v.addElement(children[i]);
233                                         }
234                                         
235                                         IJavaElement[] result= new IJavaElement[v.size()];
236                                         v.copyInto(result);
237                                         return result;
238                                 }
239                                 
240                                 public Object[] getChildren(Object parent) {
241                                         if (parent instanceof IParent) {
242                                                 IParent c= (IParent) parent;
243                                                 try {
244                                                         return filter(c.getChildren());
245                                                 } catch (JavaModelException x) {
246                                                         PHPeclipsePlugin.log(x);
247                                                 }
248                                         }
249                                         return NO_CHILDREN;
250                                 }
251                                 
252                                 public Object[] getElements(Object parent) {
253                                         if (fTopLevelTypeOnly) {
254                                                 if (parent instanceof ICompilationUnit) {
255                                                         try {
256                                                                 IType type= getMainType((ICompilationUnit) parent);
257                                                                 return type != null ? type.getChildren() : NO_CLASS;
258                                                         } catch (JavaModelException e) {
259                                                                 PHPeclipsePlugin.log(e);
260                                                         }
261                                                 } 
262 //                                              else if (parent instanceof IClassFile) {
263 //                                                      try {
264 //                                                              IType type= getMainType((IClassFile) parent);
265 //                                                              return type != null ? type.getChildren() : NO_CLASS;
266 //                                                      } catch (JavaModelException e) {
267 //                                                              JavaPlugin.log(e);
268 //                                                      }                                                       
269 //                                              }
270                                         }
271                                         return getChildren(parent);
272                                 }
273                                 
274                                 public Object getParent(Object child) {
275                                         if (child instanceof IJavaElement) {
276                                                 IJavaElement e= (IJavaElement) child;
277                                                 return e.getParent();
278                                         }
279                                         return null;
280                                 }
281                                 
282                                 public boolean hasChildren(Object parent) {
283                                         if (parent instanceof IParent) {
284                                                 IParent c= (IParent) parent;
285                                                 try {
286                                                         IJavaElement[] children= filter(c.getChildren());
287                                                         return (children != null && children.length > 0);
288                                                 } catch (JavaModelException x) {
289                                                         PHPeclipsePlugin.log(x);
290                                                 }
291                                         }
292                                         return false;
293                                 }
294                                 
295                                 public boolean isDeleted(Object o) {
296                                         return false;
297                                 }
298                                 
299                                 public void dispose() {
300                                         if (fListener != null) {
301                                                 PHPCore.removeElementChangedListener(fListener);
302                                                 fListener= null;
303                                         }               
304                                 }
305                                 
306                                 /*
307                                  * @see IContentProvider#inputChanged(Viewer, Object, Object)
308                                  */
309                                 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
310                                         boolean isCU= (newInput instanceof ICompilationUnit);
311                                                                         
312                                         if (isCU && fListener == null) {
313                                                 fListener= new ElementChangedListener();
314                                                 PHPCore.addElementChangedListener(fListener);
315                                         } else if (!isCU && fListener != null) {
316                                                 PHPCore.removeElementChangedListener(fListener);
317                                                 fListener= null;
318                                         }
319                                 }
320                         };
321                         
322                         
323                         class JavaOutlineViewer extends TreeViewer {
324                                 
325                                 /**
326                                  * Indicates an item which has been reused. At the point of
327                                  * its reuse it has been expanded. This field is used to
328                                  * communicate between <code>internalExpandToLevel</code> and
329                                  * <code>reuseTreeItem</code>.
330                                  */
331                                 private Item fReusedExpandedItem;
332                                 private boolean fReorderedMembers;
333                                 
334                                 public JavaOutlineViewer(Tree tree) {
335                                         super(tree);
336                                         setAutoExpandLevel(ALL_LEVELS);
337                                 }
338                                 
339                                 /**
340                                  * Investigates the given element change event and if affected incrementally
341                                  * updates the outline.
342                                  */
343                                 public void reconcile(IJavaElementDelta delta) {
344                                         fReorderedMembers= false;
345                                         if (getSorter() == null) {
346                                                 if (fTopLevelTypeOnly
347                                                         && delta.getElement() instanceof IType
348                                                         && (delta.getKind() & IJavaElementDelta.ADDED) != 0)
349                                                 {
350                                                         refresh(true);
351
352                                                 } else {
353                                                         Widget w= findItem(fInput);
354                                                         if (w != null && !w.isDisposed())
355                                                                 update(w, delta);
356                                                         if (fReorderedMembers) {
357                                                                 refresh(false);
358                                                                 fReorderedMembers= false;
359                                                 }
360                                                 }
361                                         } else {
362                                                 // just for now
363                                                 refresh(true);
364                                         }
365                                 }
366                                 
367                                 /*
368                                  * @see TreeViewer#internalExpandToLevel
369                                  */
370                                 protected void internalExpandToLevel(Widget node, int level) {
371                                         if (node instanceof Item) {
372                                                 Item i= (Item) node;
373                                                 if (i.getData() instanceof IJavaElement) {
374                                                         IJavaElement je= (IJavaElement) i.getData();
375                                                         if (je.getElementType() == IJavaElement.IMPORT_CONTAINER || isInnerType(je)) {
376                                                                 if (i != fReusedExpandedItem) {
377                                                                         setExpanded(i, false);
378                                                                         return;
379                                                                 }
380                                                         }
381                                                 }
382                                         }
383                                         super.internalExpandToLevel(node, level);
384                                 }
385                                                                 
386                                 protected void reuseTreeItem(Item item, Object element) {
387                                         
388                                         // remove children
389                                         Item[] c= getChildren(item);
390                                         if (c != null && c.length > 0) {
391                                                 
392                                                 if (getExpanded(item))
393                                                         fReusedExpandedItem= item;
394                                                 
395                                                 for (int k= 0; k < c.length; k++) {
396                                                         if (c[k].getData() != null)
397                                                                 disassociate(c[k]);
398                                                         c[k].dispose();
399                                                 }
400                                         }
401                                         
402                                         updateItem(item, element);
403                                         updatePlus(item, element);                                      
404                                         internalExpandToLevel(item, ALL_LEVELS);
405                                         
406                                         fReusedExpandedItem= null;
407                                 }
408                                 
409                                 protected boolean mustUpdateParent(IJavaElementDelta delta, IJavaElement element) {
410                                         if (element instanceof IMethod) {
411                                                 if ((delta.getKind() & IJavaElementDelta.ADDED) != 0) {
412                                                         try {
413                                                                 return ((IMethod)element).isMainMethod();
414                                                         } catch (JavaModelException e) {
415                                                                 PHPeclipsePlugin.log(e.getStatus());
416                                                         }
417                                                 }
418                                                 return "main".equals(element.getElementName()); //$NON-NLS-1$
419                                         }
420                                         return false;
421                                 }
422                                 
423                                 protected ISourceRange getSourceRange(IJavaElement element) throws JavaModelException {
424                                         if (element instanceof IMember)// && !(element instanceof IInitializer))
425                                                 return ((IMember) element).getNameRange();
426                                         if (element instanceof ISourceReference)
427                                                 return ((ISourceReference) element).getSourceRange();
428                                         return null;
429                                 }
430                                 
431                                 protected boolean overlaps(ISourceRange range, int start, int end) {
432                                         return start <= (range.getOffset() + range.getLength() - 1) && range.getOffset() <= end;
433                                 }
434                                 
435                                 protected boolean filtered(IJavaElement parent, IJavaElement child) {
436                                         
437                                         Object[] result= new Object[] { child };
438                                         ViewerFilter[] filters= getFilters();
439                                         for (int i= 0; i < filters.length; i++) {
440                                                 result= filters[i].filter(this, parent, result);
441                                                 if (result.length == 0)
442                                                         return true;
443                                         }
444                                         
445                                         return false;
446                                 }
447                                 
448                                 protected void update(Widget w, IJavaElementDelta delta) {
449                                         
450                                         Item item;
451                                         
452                                         IJavaElement parent= delta.getElement();
453                                         IJavaElementDelta[] affected= delta.getAffectedChildren();
454                                         Item[] children= getChildren(w);
455
456                                         boolean doUpdateParent= false;
457                                                                                 
458                                         Vector deletions= new Vector();
459                                         Vector additions= new Vector();                         
460
461                                         for (int i= 0; i < affected.length; i++) {
462                                             IJavaElementDelta affectedDelta= affected[i];
463                                                 IJavaElement affectedElement= affectedDelta.getElement();
464                                                 int status= affected[i].getKind();
465
466                                                 // find tree item with affected element
467                                                 int j;
468                                                 for (j= 0; j < children.length; j++)
469                                                     if (affectedElement.equals(children[j].getData()))
470                                                         break;
471                                                 
472                                                 if (j == children.length) {
473                                                         // addition
474                                                         if ((status & IJavaElementDelta.CHANGED) != 0 &&                                                        
475                                                                 (affectedDelta.getFlags() & IJavaElementDelta.F_MODIFIERS) != 0 &&
476                                                                 !filtered(parent, affectedElement))
477                                                         {
478                                                                 additions.addElement(affectedDelta);
479                                                         }
480                                                         continue;
481                                                 }
482
483                                                 item= children[j];
484
485                                                 // removed                                                  
486                                                 if ((status & IJavaElementDelta.REMOVED) != 0) {
487                                                         deletions.addElement(item);
488                                                         doUpdateParent= doUpdateParent || mustUpdateParent(affectedDelta, affectedElement);
489
490                                                 // changed                                                  
491                                                 } else if ((status & IJavaElementDelta.CHANGED) != 0) {
492                                                         int change= affectedDelta.getFlags();
493                                                         doUpdateParent= doUpdateParent || mustUpdateParent(affectedDelta, affectedElement);
494                                                         
495                                                         if ((change & IJavaElementDelta.F_MODIFIERS) != 0) {
496                                                                 if (filtered(parent, affectedElement))
497                                                                         deletions.addElement(item);
498                                                                 else
499                                                                         updateItem(item, affectedElement);
500                                                         }
501                                                         
502                                                         if ((change & IJavaElementDelta.F_CONTENT) != 0)
503                                                                 updateItem(item, affectedElement);
504                                                                 
505                                                         if ((change & IJavaElementDelta.F_CHILDREN) != 0)
506                                                                 update(item, affectedDelta);                                                                                                                        
507                                                         
508                                                         if ((change & IJavaElementDelta.F_REORDER) != 0)
509                                                                 fReorderedMembers= true;
510                                                 }
511                                         }
512                                         
513                                         // find all elements to add
514                                         IJavaElementDelta[] add= delta.getAddedChildren();
515                                         if (additions.size() > 0) {
516                                                 IJavaElementDelta[] tmp= new IJavaElementDelta[add.length + additions.size()];
517                                                 System.arraycopy(add, 0, tmp, 0, add.length);
518                                                 for (int i= 0; i < additions.size(); i++)
519                                                         tmp[i + add.length]= (IJavaElementDelta) additions.elementAt(i);
520                                                 add= tmp;
521                                         }
522                                         
523                                         // add at the right position
524                                         go2: for (int i= 0; i < add.length; i++) {
525                                                 
526                                                 try {
527                                                         
528                                                         IJavaElement e= add[i].getElement();
529                                                         if (filtered(parent, e))
530                                                                 continue go2;
531                                                                 
532                                                         doUpdateParent= doUpdateParent || mustUpdateParent(add[i], e);
533                                                         ISourceRange rng= getSourceRange(e);
534                                                         int start= rng.getOffset();
535                                                         int end= start + rng.getLength() - 1;
536                                                         
537                                                         Item last= null;
538                                                         item= null;
539                                                         children= getChildren(w);
540                                                         
541                                                         for (int j= 0; j < children.length; j++) {
542                                                                 item= children[j];
543                                                                 IJavaElement r= (IJavaElement) item.getData();
544                                                                 
545                                                                 if (r == null) {
546                                                                         // parent node collapsed and not be opened before -> do nothing
547                                                                         continue go2;
548                                                                 }
549                                                                 
550                                                                         
551                                                                 try {
552                                                                         rng= getSourceRange(r);
553                                                                         if (overlaps(rng, start, end)) {
554                                                                                 
555                                                                                 // be tolerant if the delta is not correct, or if 
556                                                                                 // the tree has been updated other than by a delta
557                                                                                 reuseTreeItem(item, e);
558                                                                                 continue go2;
559                                                                                 
560                                                                         } else if (rng.getOffset() > start) {
561                                                                                 
562                                                                                 if (last != null && deletions.contains(last)) {
563                                                                                         // reuse item
564                                                                                         deletions.removeElement(last);
565                                                                                         reuseTreeItem(last, (Object) e);
566                                                                                 } else {
567                                                                                         // nothing to reuse
568                                                                                         createTreeItem(w, (Object) e, j);
569                                                                                 }
570                                                                                 continue go2;
571                                                                         }
572                                                                         
573                                                                 } catch (JavaModelException x) {
574                                                                         // stumbled over deleted element
575                                                                 }
576                                                                 
577                                                                 last= item;
578                                                         }
579                                                 
580                                                         // add at the end of the list
581                                                         if (last != null && deletions.contains(last)) {
582                                                                 // reuse item
583                                                                 deletions.removeElement(last);
584                                                                 reuseTreeItem(last, e);
585                                                         } else {
586                                                                 // nothing to reuse
587                                                                 createTreeItem(w, e, -1);
588                                                         }
589                                                 
590                                                 } catch (JavaModelException x) {
591                                                         // the element to be added is not present -> don't add it
592                                                 }
593                                         }
594                                         
595                                         
596                                         // remove items which haven't been reused
597                                         Enumeration e= deletions.elements();
598                                         while (e.hasMoreElements()) {
599                                                 item= (Item) e.nextElement();
600                                                 disassociate(item);
601                                                 item.dispose();
602                                         }
603                                         
604                                         if (doUpdateParent)
605                                                 updateItem(w, delta.getElement());
606                                 }
607                                 
608
609                                                                 
610                                 /*
611                                  * @see ContentViewer#handleLabelProviderChanged(LabelProviderChangedEvent)
612                                  */
613                                 protected void handleLabelProviderChanged(LabelProviderChangedEvent event) {
614                                         Object input= getInput();
615                                         if (event instanceof ProblemsLabelChangedEvent) {
616                                                 ProblemsLabelChangedEvent e= (ProblemsLabelChangedEvent) event;
617                                                 if (e.isMarkerChange() && input instanceof ICompilationUnit) {
618                                                         return; // marker changes can be ignored
619                                                 }
620                                         }
621                                         // look if the underlying resource changed
622                                         Object[] changed= event.getElements();
623                                         if (changed != null) {
624                                                 IResource resource= getUnderlyingResource();
625                                                 if (resource != null) {
626                                                         for (int i= 0; i < changed.length; i++) {
627                                                                 if (changed[i] != null && changed[i].equals(resource)) {
628                                                                         // change event to a full refresh
629                                                                         event= new LabelProviderChangedEvent((IBaseLabelProvider) event.getSource());
630                                                                         break;
631                                                                 }
632                                                         }
633                                                 }
634                                         }
635                                         super.handleLabelProviderChanged(event);
636                                 }
637                                 
638                                 private IResource getUnderlyingResource() {
639                                         Object input= getInput();
640                                         if (input instanceof ICompilationUnit) {
641                                                 ICompilationUnit cu= (ICompilationUnit) input;
642                                                 if (cu.isWorkingCopy()) {
643                                                         return cu.getOriginalElement().getResource();
644                                                 } else {
645                                                         return cu.getResource();
646                                                 }                               
647                                         } 
648 //                                      else if (input instanceof IClassFile) {
649 //                                              return ((IClassFile) input).getResource();
650 //                                      }
651                                         return null;
652                                 }                               
653                                 
654
655                         };
656                                 
657                         class LexicalSortingAction extends Action {
658                                 
659                                 private JavaElementSorter fSorter= new JavaElementSorter();                     
660
661                                 public LexicalSortingAction() {
662                                         super();
663 //                                      WorkbenchHelp.setHelp(this, IJavaHelpContextIds.LEXICAL_SORTING_OUTLINE_ACTION);
664                                         setText(PHPEditorMessages.getString("JavaOutlinePage.Sort.label")); //$NON-NLS-1$
665                                         PHPUiImages.setLocalImageDescriptors(this, "alphab_sort_co.gif"); //$NON-NLS-1$
666                                         setToolTipText(PHPEditorMessages.getString("JavaOutlinePage.Sort.tooltip")); //$NON-NLS-1$
667                                         setDescription(PHPEditorMessages.getString("JavaOutlinePage.Sort.description")); //$NON-NLS-1$
668                                         
669                                         boolean checked= PHPeclipsePlugin.getDefault().getPreferenceStore().getBoolean("LexicalSortingAction.isChecked"); //$NON-NLS-1$
670                                         valueChanged(checked, false);
671                                 }
672                                 
673                                 public void run() {
674                                         valueChanged(isChecked(), true);
675                                 }
676                                 
677                                 private void valueChanged(final boolean on, boolean store) {
678                                         setChecked(on);
679                                         BusyIndicator.showWhile(fOutlineViewer.getControl().getDisplay(), new Runnable() {
680                                                 public void run() {
681                                                         fOutlineViewer.setSorter(on ? fSorter : null);                                          }
682                                         });
683
684                                         if (store)
685                                         PHPeclipsePlugin.getDefault().getPreferenceStore().setValue("LexicalSortingAction.isChecked", on); //$NON-NLS-1$
686                                 }
687                         };
688
689                 class ClassOnlyAction extends Action {
690
691                         public ClassOnlyAction() {
692                                 super();
693 //                              WorkbenchHelp.setHelp(this, IJavaHelpContextIds.GO_INTO_TOP_LEVEL_TYPE_ACTION);
694                                 setText(PHPEditorMessages.getString("JavaOutlinePage.GoIntoTopLevelType.label")); //$NON-NLS-1$
695                                 setToolTipText(PHPEditorMessages.getString("JavaOutlinePage.GoIntoTopLevelType.tooltip")); //$NON-NLS-1$
696                                 setDescription(PHPEditorMessages.getString("JavaOutlinePage.GoIntoTopLevelType.description")); //$NON-NLS-1$
697                                 PHPUiImages.setLocalImageDescriptors(this, "gointo_toplevel_type.gif"); //$NON-NLS-1$
698
699                                 IPreferenceStore preferenceStore= PHPeclipsePlugin.getDefault().getPreferenceStore();
700                                 boolean showclass= preferenceStore.getBoolean("GoIntoTopLevelTypeAction.isChecked"); //$NON-NLS-1$
701                                 setTopLevelTypeOnly(showclass);
702                         }
703
704                         /*
705                          * @see org.eclipse.jface.action.Action#run()
706                          */
707                         public void run() {
708                                 setTopLevelTypeOnly(!fTopLevelTypeOnly);
709                         }
710
711                         private void setTopLevelTypeOnly(boolean show) {
712                                 fTopLevelTypeOnly= show;
713                                 setChecked(show);
714                                 fOutlineViewer.refresh(false);
715                                 
716                                 IPreferenceStore preferenceStore= PHPeclipsePlugin.getDefault().getPreferenceStore(); 
717                                 preferenceStore.setValue("GoIntoTopLevelTypeAction.isChecked", show); //$NON-NLS-1$
718                         }
719                 };
720
721         /** A flag to show contents of top level type only */
722         private boolean fTopLevelTypeOnly;
723                         
724         private IJavaElement fInput;
725         private String fContextMenuID;
726         private Menu fMenu;
727         private JavaOutlineViewer fOutlineViewer;
728         private PHPEditor fEditor;
729         
730         private MemberFilterActionGroup fMemberFilterActionGroup;
731                 
732         private ListenerList fSelectionChangedListeners= new ListenerList();
733         private Hashtable fActions= new Hashtable();
734         
735         private TogglePresentationAction fTogglePresentation;
736         private GotoErrorAction fPreviousError;
737         private GotoErrorAction fNextError;
738         private TextEditorAction fShowJavadoc;
739         private TextOperationAction fUndo;
740         private TextOperationAction fRedo;
741         
742         private CompositeActionGroup fActionGroups;
743 //      private CCPActionGroup fCCPActionGroup;
744
745         private IPropertyChangeListener fPropertyChangeListener;
746         
747         public JavaOutlinePage(String contextMenuID, PHPEditor editor) {
748                 super();
749                 
750                 Assert.isNotNull(editor);
751                 
752                 fContextMenuID= contextMenuID;
753                 fEditor= editor;
754                 
755                 fTogglePresentation= new TogglePresentationAction();
756                 fPreviousError= new GotoErrorAction("PreviousError.", false); //$NON-NLS-1$
757                 fPreviousError.setImageDescriptor(PHPUiImages.DESC_TOOL_GOTO_PREV_ERROR);
758                 fNextError= new GotoErrorAction("NextError.", true); //$NON-NLS-1$
759                 fNextError.setImageDescriptor(PHPUiImages.DESC_TOOL_GOTO_NEXT_ERROR);
760                 fShowJavadoc= (TextEditorAction) fEditor.getAction("ShowJavaDoc"); //$NON-NLS-1$
761                 fUndo= (TextOperationAction) fEditor.getAction(ITextEditorActionConstants.UNDO);
762                 fRedo= (TextOperationAction) fEditor.getAction(ITextEditorActionConstants.REDO);
763                 
764                 fTogglePresentation.setEditor(editor);
765                 fPreviousError.setEditor(editor);
766                 fNextError.setEditor(editor);   
767                 
768                 fPropertyChangeListener= new IPropertyChangeListener() {
769                         public void propertyChange(PropertyChangeEvent event) {
770                                 doPropertyChange(event);
771                         }
772                 };
773                 PHPeclipsePlugin.getDefault().getPreferenceStore().addPropertyChangeListener(fPropertyChangeListener);
774         }
775    
776         /**
777          * Returns the primary type of a compilation unit (has the same
778          * name as the compilation unit).
779          * 
780          * @param compilationUnit the compilation unit
781          * @return returns the primary type of the compilation unit, or
782          * <code>null</code> if is does not have one
783          */
784         protected IType getMainType(ICompilationUnit compilationUnit) {
785                 String name= compilationUnit.getElementName();
786                 int index= name.indexOf('.');
787                 if (index != -1)
788                         name= name.substring(0, index);
789                 IType type= compilationUnit.getType(name);
790                 return type.exists() ? type : null;
791         }
792
793         /**
794          * Returns the primary type of a class file.
795          * 
796          * @param classFile the class file
797          * @return returns the primary type of the class file, or <code>null</code>
798          * if is does not have one
799          */
800 //      protected IType getMainType(IClassFile classFile) {
801 //              try {
802 //                      IType type= classFile.getType();
803 //                      return type != null && type.exists() ? type : null;
804 //              } catch (JavaModelException e) {
805 //                      return null;    
806 //              }
807 //      }
808         
809         /* (non-Javadoc)
810          * Method declared on Page
811          */
812         public void init(IPageSite pageSite) {
813                 super.init(pageSite);
814         }
815         
816         private void doPropertyChange(PropertyChangeEvent event) {
817                 if (fOutlineViewer != null) {
818                         if (PreferenceConstants.APPEARANCE_MEMBER_SORT_ORDER.equals(event.getProperty())) {
819                                 fOutlineViewer.refresh(false);
820                         }
821                 }
822         }       
823         
824         /*
825          * @see ISelectionProvider#addSelectionChangedListener(ISelectionChangedListener)
826          */
827         public void addSelectionChangedListener(ISelectionChangedListener listener) {
828                 if (fOutlineViewer != null)
829                         fOutlineViewer.addPostSelectionChangedListener(listener);
830                 else
831                         fSelectionChangedListeners.add(listener);
832         }
833         
834         /*
835          * @see ISelectionProvider#removeSelectionChangedListener(ISelectionChangedListener)
836          */
837         public void removeSelectionChangedListener(ISelectionChangedListener listener) {
838                 if (fOutlineViewer != null)
839                         fOutlineViewer.removePostSelectionChangedListener(listener);
840                 else
841                         fSelectionChangedListeners.remove(listener);
842         }
843         
844         /*
845          * @see ISelectionProvider#setSelection(ISelection)
846          */
847         public void setSelection(ISelection selection) {
848                 if (fOutlineViewer != null)
849                         fOutlineViewer.setSelection(selection);         
850         }       
851         
852         /*
853          * @see ISelectionProvider#getSelection()
854          */
855         public ISelection getSelection() {
856                 if (fOutlineViewer == null)
857                         return StructuredSelection.EMPTY;
858                 return fOutlineViewer.getSelection();
859         }
860         
861         private void registerToolbarActions() {
862                 
863                 IToolBarManager toolBarManager= getSite().getActionBars().getToolBarManager();
864                 if (toolBarManager != null) {   
865                         toolBarManager.add(new ClassOnlyAction());              
866                         toolBarManager.add(new LexicalSortingAction());
867                         
868                         fMemberFilterActionGroup= new MemberFilterActionGroup(fOutlineViewer, "JavaOutlineViewer"); //$NON-NLS-1$
869                         fMemberFilterActionGroup.contributeToToolBar(toolBarManager);
870                 }
871         }
872         
873         /*
874          * @see IPage#createControl
875          */
876         public void createControl(Composite parent) {
877                 
878                 Tree tree= new Tree(parent, SWT.MULTI);
879
880                 AppearanceAwareLabelProvider lprovider= new AppearanceAwareLabelProvider(
881                         AppearanceAwareLabelProvider.DEFAULT_TEXTFLAGS |  JavaElementLabels.F_APP_TYPE_SIGNATURE,
882                         AppearanceAwareLabelProvider.DEFAULT_IMAGEFLAGS
883                 );
884
885                 fOutlineViewer= new JavaOutlineViewer(tree);            
886                 fOutlineViewer.setContentProvider(new ChildrenProvider());
887                 fOutlineViewer.setLabelProvider(new DecoratingJavaLabelProvider(lprovider));
888                 
889                 Object[] listeners= fSelectionChangedListeners.getListeners();
890                 for (int i= 0; i < listeners.length; i++) {
891                         fSelectionChangedListeners.remove(listeners[i]);
892                         fOutlineViewer.addPostSelectionChangedListener((ISelectionChangedListener) listeners[i]);
893                 }
894                                 
895                 MenuManager manager= new MenuManager(fContextMenuID, fContextMenuID);
896                 manager.setRemoveAllWhenShown(true);
897                 manager.addMenuListener(new IMenuListener() {
898                         public void menuAboutToShow(IMenuManager manager) {
899                                 contextMenuAboutToShow(manager);
900                         }
901                 });
902                 fMenu= manager.createContextMenu(tree);
903                 tree.setMenu(fMenu);
904                 
905                 IPageSite site= getSite();
906                 site.registerContextMenu(PHPeclipsePlugin.getPluginId() + ".outline", manager, fOutlineViewer); //$NON-NLS-1$
907                 site.setSelectionProvider(fOutlineViewer);
908
909                 // we must create the groups after we have set the selection provider to the site
910                 fActionGroups= new CompositeActionGroup(new ActionGroup[] {
911 //                              new OpenViewActionGroup(this), 
912 //                              fCCPActionGroup= new CCPActionGroup(this),
913                                 new GenerateActionGroup(this)});
914 //                              new RefactorActionGroup(this), 
915 //                              new JavaSearchActionGroup(this)});
916                                 
917                 // register global actions
918                 IActionBars bars= site.getActionBars();
919                 
920                 bars.setGlobalActionHandler(ITextEditorActionConstants.UNDO, fUndo);
921                 bars.setGlobalActionHandler(ITextEditorActionConstants.REDO, fRedo);
922                 bars.setGlobalActionHandler(ITextEditorActionConstants.PREVIOUS, fPreviousError);
923                 bars.setGlobalActionHandler(ITextEditorActionConstants.NEXT, fNextError);
924 //              bars.setGlobalActionHandler(PHPdtActionConstants.SHOW_PHP_DOC, fShowJavadoc);
925                 bars.setGlobalActionHandler(IJavaEditorActionConstants.TOGGLE_PRESENTATION, fTogglePresentation);
926                 // http://dev.eclipse.org/bugs/show_bug.cgi?id=18968
927                 bars.setGlobalActionHandler(IJavaEditorActionConstants.PREVIOUS_ERROR, fPreviousError);
928                 bars.setGlobalActionHandler(IJavaEditorActionConstants.NEXT_ERROR, fNextError);
929                 
930                 fActionGroups.fillActionBars(bars);
931
932                 IStatusLineManager statusLineManager= site.getActionBars().getStatusLineManager();
933                 if (statusLineManager != null) {
934                         StatusBarUpdater updater= new StatusBarUpdater(statusLineManager);
935                         fOutlineViewer.addPostSelectionChangedListener(updater);
936                 }
937                 
938                 registerToolbarActions();
939                                 
940                 fOutlineViewer.setInput(fInput);        
941                 fOutlineViewer.getControl().addKeyListener(new KeyAdapter() {
942                         public void keyPressed(KeyEvent e) {
943                                 handleKeyReleased(e);
944                         }
945                 });
946                 
947                 initDragAndDrop();
948         }
949
950         public void dispose() {
951                 
952                 if (fEditor == null)
953                         return;
954                         
955                 if (fMemberFilterActionGroup != null) {
956                         fMemberFilterActionGroup.dispose();
957                         fMemberFilterActionGroup= null;
958                 }
959                         
960                         
961                 fEditor.outlinePageClosed();
962                 fEditor= null;
963
964                 fSelectionChangedListeners.clear();
965                 fSelectionChangedListeners= null;
966
967                 if (fPropertyChangeListener != null) {
968                         PHPeclipsePlugin.getDefault().getPreferenceStore().removePropertyChangeListener(fPropertyChangeListener);
969                         fPropertyChangeListener= null;
970                 }
971                 
972                 if (fMenu != null && !fMenu.isDisposed()) {
973                         fMenu.dispose();
974                         fMenu= null;
975                 }
976                 
977                 if (fActionGroups != null)
978                         fActionGroups.dispose();
979                         
980                 fTogglePresentation.setEditor(null);
981                 fPreviousError.setEditor(null);
982                 fNextError.setEditor(null);     
983                 
984                 fOutlineViewer= null;
985                 
986                 super.dispose();
987         }
988         
989         public Control getControl() {
990                 if (fOutlineViewer != null)
991                         return fOutlineViewer.getControl();
992                 return null;
993         }
994         
995         public void setInput(IJavaElement inputElement) {
996                 fInput= inputElement;   
997                 if (fOutlineViewer != null)
998                         fOutlineViewer.setInput(fInput);
999         }
1000                 
1001         public void select(ISourceReference reference) {
1002                 if (fOutlineViewer != null) {
1003                         
1004                         ISelection s= fOutlineViewer.getSelection();
1005                         if (s instanceof IStructuredSelection) {
1006                                 IStructuredSelection ss= (IStructuredSelection) s;
1007                                 List elements= ss.toList();
1008                                 if (!elements.contains(reference)) {
1009                                         s= (reference == null ? StructuredSelection.EMPTY : new StructuredSelection(reference));
1010                                         fOutlineViewer.setSelection(s, true);
1011                                 }
1012                         }
1013                 }
1014         }
1015         
1016         public void setAction(String actionID, IAction action) {
1017                 Assert.isNotNull(actionID);
1018                 if (action == null)
1019                         fActions.remove(actionID);
1020                 else
1021                         fActions.put(actionID, action);
1022         }
1023         
1024         public IAction getAction(String actionID) {
1025                 Assert.isNotNull(actionID);
1026                 return (IAction) fActions.get(actionID);
1027         }
1028
1029         /**
1030          * Answer the property defined by key.
1031          */
1032         public Object getAdapter(Class key) {
1033                 if (key == IShowInSource.class) {
1034                         return getShowInSource();
1035                 }
1036                 if (key == IShowInTargetList.class) {
1037                         return new IShowInTargetList() {
1038                                 public String[] getShowInTargetIds() {
1039                                         return new String[] { JavaUI.ID_PACKAGES };
1040                                 }
1041
1042                         };
1043                 }
1044                 if (key == IShowInTarget.class) {
1045                         return getShowInTarget();
1046                 }
1047
1048                 return null;
1049         }
1050
1051         /**
1052          * Convenience method to add the action installed under the given actionID to the
1053          * specified group of the menu.
1054          */
1055         protected void addAction(IMenuManager menu, String group, String actionID) {
1056                 IAction action= getAction(actionID);
1057                 if (action != null) {
1058                         if (action instanceof IUpdate)
1059                                 ((IUpdate) action).update();
1060                                 
1061                         if (action.isEnabled()) {
1062                                 IMenuManager subMenu= menu.findMenuUsingPath(group);
1063                                 if (subMenu != null)
1064                                         subMenu.add(action);
1065                                 else
1066                                         menu.appendToGroup(group, action);
1067                         }
1068                 }
1069         }
1070          
1071         protected void contextMenuAboutToShow(IMenuManager menu) {
1072                 
1073                 PHPeclipsePlugin.createStandardGroups(menu);
1074                                 
1075                 IStructuredSelection selection= (IStructuredSelection)getSelection();
1076                 fActionGroups.setContext(new ActionContext(selection));
1077                 fActionGroups.fillContextMenu(menu);
1078         }
1079         
1080         /*
1081          * @see Page#setFocus()
1082          */
1083         public void setFocus() {
1084                 if (fOutlineViewer != null)
1085                         fOutlineViewer.getControl().setFocus();
1086         }
1087         
1088         /**
1089          * Checkes whether a given Java element is an inner type.
1090          */
1091         private boolean isInnerType(IJavaElement element) {
1092                 
1093                 if (element.getElementType() == IJavaElement.TYPE) {
1094                         IJavaElement parent= element.getParent();
1095                         int type= parent.getElementType();
1096                         return (type != IJavaElement.COMPILATION_UNIT && type != IJavaElement.CLASS_FILE);
1097                 }
1098                 
1099                 return false;           
1100         }
1101         
1102         /**
1103          * Handles key events in viewer.
1104          */
1105         private void handleKeyReleased(KeyEvent event) {
1106                 
1107                 if (event.stateMask != 0)
1108                         return;
1109                 
1110                 IAction action= null;
1111 //              if (event.character == SWT.DEL) {
1112 //                      action= fCCPActionGroup.getDeleteAction();
1113 //              }
1114                         
1115                 if (action != null && action.isEnabled())
1116                         action.run();
1117         }
1118         
1119         /**
1120          * Returns the <code>IShowInSource</code> for this view.
1121          */
1122         protected IShowInSource getShowInSource() {
1123                 return new IShowInSource() {
1124                         public ShowInContext getShowInContext() {
1125                                 return new ShowInContext(
1126                                         null,
1127                                         getSite().getSelectionProvider().getSelection());
1128                         }
1129                 };
1130         }
1131
1132         /**
1133          * Returns the <code>IShowInTarget</code> for this view.
1134          */
1135         protected IShowInTarget getShowInTarget() {
1136                 return new IShowInTarget() {
1137                         public boolean show(ShowInContext context) {
1138                                 ISelection sel= context.getSelection();
1139                                 if (sel instanceof ITextSelection) {
1140                                         ITextSelection tsel= (ITextSelection) sel;
1141                                         int offset= tsel.getOffset();
1142                                         IJavaElement element= fEditor.getElementAt(offset);
1143                                         if (element != null) {
1144                                                 setSelection(new StructuredSelection(element));
1145                                                 return true;
1146                                         }
1147                                 }
1148                                 return false;
1149                         }
1150                 };
1151         }
1152         
1153         private void initDragAndDrop() {
1154                 int ops= DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
1155                 Transfer[] transfers= new Transfer[] {
1156                         LocalSelectionTransfer.getInstance()
1157                         };
1158                 
1159                 // Drop Adapter
1160 //              TransferDropTargetListener[] dropListeners= new TransferDropTargetListener[] {
1161 //                      new SelectionTransferDropAdapter(fOutlineViewer)
1162 //              };
1163 //              fOutlineViewer.addDropSupport(ops | DND.DROP_DEFAULT, transfers, new DelegatingDropAdapter(dropListeners));
1164                 
1165                 // Drag Adapter
1166                 TransferDragSourceListener[] dragListeners= new TransferDragSourceListener[] {
1167                         new SelectionTransferDragAdapter(fOutlineViewer)
1168                 };
1169                 fOutlineViewer.addDragSupport(ops, transfers, new JdtViewerDragAdapter(fOutlineViewer, dragListeners));
1170         }
1171 }