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