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