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