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