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