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