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