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