1 /*******************************************************************************
 
   2  * Copyright (c) 2000, 2003 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
 
   9  *     IBM Corporation - initial API and implementation
 
  10  *******************************************************************************/
 
  11 package net.sourceforge.phpeclipse.phpeditor;
 
  13 import java.util.Enumeration;
 
  14 import java.util.Hashtable;
 
  15 import java.util.List;
 
  16 import java.util.Vector;
 
  18 import net.sourceforge.phpdt.core.ElementChangedEvent;
 
  19 import net.sourceforge.phpdt.core.ICompilationUnit;
 
  20 import net.sourceforge.phpdt.core.IElementChangedListener;
 
  21 import net.sourceforge.phpdt.core.IJavaElement;
 
  22 import net.sourceforge.phpdt.core.IJavaElementDelta;
 
  23 import net.sourceforge.phpdt.core.IMember;
 
  24 import net.sourceforge.phpdt.core.IParent;
 
  25 import net.sourceforge.phpdt.core.ISourceRange;
 
  26 import net.sourceforge.phpdt.core.ISourceReference;
 
  27 import net.sourceforge.phpdt.core.IType;
 
  28 import net.sourceforge.phpdt.core.JavaCore;
 
  29 import net.sourceforge.phpdt.core.JavaModelException;
 
  30 import net.sourceforge.phpdt.internal.ui.PHPUiImages;
 
  31 import net.sourceforge.phpdt.internal.ui.actions.AbstractToggleLinkingAction;
 
  32 import net.sourceforge.phpdt.internal.ui.actions.CompositeActionGroup;
 
  33 import net.sourceforge.phpdt.internal.ui.dnd.JdtViewerDragAdapter;
 
  34 import net.sourceforge.phpdt.internal.ui.dnd.TransferDragSourceListener;
 
  35 import net.sourceforge.phpdt.internal.ui.packageview.SelectionTransferDragAdapter;
 
  36 import net.sourceforge.phpdt.internal.ui.viewsupport.AppearanceAwareLabelProvider;
 
  37 import net.sourceforge.phpdt.internal.ui.viewsupport.DecoratingJavaLabelProvider;
 
  38 import net.sourceforge.phpdt.internal.ui.viewsupport.JavaElementLabels;
 
  39 import net.sourceforge.phpdt.internal.ui.viewsupport.StatusBarUpdater;
 
  40 import net.sourceforge.phpdt.ui.JavaElementSorter;
 
  41 import net.sourceforge.phpdt.ui.JavaUI;
 
  42 import net.sourceforge.phpdt.ui.PreferenceConstants;
 
  43 import net.sourceforge.phpdt.ui.ProblemsLabelDecorator.ProblemsLabelChangedEvent;
 
  44 import net.sourceforge.phpdt.ui.actions.GenerateActionGroup;
 
  45 import net.sourceforge.phpdt.ui.actions.MemberFilterActionGroup;
 
  46 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
 
  48 import org.eclipse.core.resources.IResource;
 
  49 import org.eclipse.core.runtime.IAdaptable;
 
  50 import org.eclipse.jface.action.Action;
 
  51 import org.eclipse.jface.action.IAction;
 
  52 import org.eclipse.jface.action.IMenuListener;
 
  53 import org.eclipse.jface.action.IMenuManager;
 
  54 import org.eclipse.jface.action.IStatusLineManager;
 
  55 import org.eclipse.jface.action.IToolBarManager;
 
  56 import org.eclipse.jface.action.MenuManager;
 
  57 import org.eclipse.jface.action.Separator;
 
  58 import org.eclipse.jface.preference.IPreferenceStore;
 
  59 import org.eclipse.jface.text.Assert;
 
  60 import org.eclipse.jface.text.ITextSelection;
 
  61 import org.eclipse.jface.util.IPropertyChangeListener;
 
  62 import org.eclipse.jface.util.ListenerList;
 
  63 import org.eclipse.jface.util.PropertyChangeEvent;
 
  64 import org.eclipse.jface.viewers.IBaseLabelProvider;
 
  65 import org.eclipse.jface.viewers.IPostSelectionProvider;
 
  66 import org.eclipse.jface.viewers.ISelection;
 
  67 import org.eclipse.jface.viewers.ISelectionChangedListener;
 
  68 import org.eclipse.jface.viewers.IStructuredSelection;
 
  69 import org.eclipse.jface.viewers.ITreeContentProvider;
 
  70 import org.eclipse.jface.viewers.LabelProviderChangedEvent;
 
  71 import org.eclipse.jface.viewers.SelectionChangedEvent;
 
  72 import org.eclipse.jface.viewers.StructuredSelection;
 
  73 import org.eclipse.jface.viewers.TreeViewer;
 
  74 import org.eclipse.jface.viewers.Viewer;
 
  75 import org.eclipse.jface.viewers.ViewerFilter;
 
  76 import org.eclipse.swt.SWT;
 
  77 import org.eclipse.swt.custom.BusyIndicator;
 
  78 import org.eclipse.swt.dnd.DND;
 
  79 import org.eclipse.swt.dnd.Transfer;
 
  80 import org.eclipse.swt.events.KeyEvent;
 
  81 import org.eclipse.swt.widgets.Composite;
 
  82 import org.eclipse.swt.widgets.Control;
 
  83 import org.eclipse.swt.widgets.Display;
 
  84 import org.eclipse.swt.widgets.Item;
 
  85 import org.eclipse.swt.widgets.Menu;
 
  86 import org.eclipse.swt.widgets.Tree;
 
  87 import org.eclipse.swt.widgets.Widget;
 
  88 import org.eclipse.ui.IActionBars;
 
  89 import org.eclipse.ui.actions.ActionContext;
 
  90 import org.eclipse.ui.actions.ActionGroup;
 
  91 import org.eclipse.ui.model.IWorkbenchAdapter;
 
  92 import org.eclipse.ui.model.WorkbenchAdapter;
 
  93 import org.eclipse.ui.part.IPageSite;
 
  94 import org.eclipse.ui.part.IShowInSource;
 
  95 import org.eclipse.ui.part.IShowInTarget;
 
  96 import org.eclipse.ui.part.IShowInTargetList;
 
  97 import org.eclipse.ui.part.Page;
 
  98 import org.eclipse.ui.part.ShowInContext;
 
  99 import org.eclipse.ui.texteditor.ITextEditorActionConstants;
 
 100 import org.eclipse.ui.texteditor.IUpdate;
 
 101 import org.eclipse.ui.texteditor.TextEditorAction;
 
 102 import org.eclipse.ui.texteditor.TextOperationAction;
 
 103 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
 
 104 import org.eclipse.ui.views.navigator.LocalSelectionTransfer;
 
 107  * The content outline page of the Java editor. The viewer implements a proprietary update mechanism based on Java model deltas. It
 
 108  * does not react on domain changes. It is specified to show the content of ICompilationUnits and IClassFiles. Pulishes its context
 
 109  * menu under <code>JavaPlugin.getDefault().getPluginId() + ".outline"</code>.
 
 111 public class JavaOutlinePage extends Page implements IContentOutlinePage, IAdaptable, IPostSelectionProvider {
 
 113   static Object[] NO_CHILDREN = new Object[0];
 
 116    * The element change listener of the java outline viewer.
 
 118    * @see IElementChangedListener
 
 120   class ElementChangedListener implements IElementChangedListener {
 
 122     public void elementChanged(final ElementChangedEvent e) {
 
 124       if (getControl() == null)
 
 127       Display d = getControl().getDisplay();
 
 129         d.asyncExec(new Runnable() {
 
 131             ICompilationUnit cu = (ICompilationUnit) fInput;
 
 132             IJavaElement base = cu;
 
 133             if (fTopLevelTypeOnly) {
 
 134               base = getMainType(cu);
 
 136                 if (fOutlineViewer != null)
 
 137                   fOutlineViewer.refresh(true);
 
 141             IJavaElementDelta delta = findElement(base, e.getDelta());
 
 142             if (delta != null && fOutlineViewer != null) {
 
 143               fOutlineViewer.reconcile(delta);
 
 150     protected IJavaElementDelta findElement(IJavaElement unit, IJavaElementDelta delta) {
 
 152       if (delta == null || unit == null)
 
 155       IJavaElement element = delta.getElement();
 
 157       if (unit.equals(element))
 
 160       if (element.getElementType() > IJavaElement.CLASS_FILE)
 
 163       IJavaElementDelta[] children = delta.getAffectedChildren();
 
 164       if (children == null || children.length == 0)
 
 167       for (int i = 0; i < children.length; i++) {
 
 168         IJavaElementDelta d = findElement(unit, children[i]);
 
 177   static class NoClassElement extends WorkbenchAdapter implements IAdaptable {
 
 179      * @see java.lang.Object#toString()
 
 181     public String toString() {
 
 182       return PHPEditorMessages.getString("JavaOutlinePage.error.NoTopLevelType"); //$NON-NLS-1$
 
 186      * @see org.eclipse.core.runtime.IAdaptable#getAdapter(Class)
 
 188     public Object getAdapter(Class clas) {
 
 189       if (clas == IWorkbenchAdapter.class)
 
 196    * Content provider for the children of an ICompilationUnit or an IClassFile
 
 198    * @see ITreeContentProvider
 
 200   class ChildrenProvider implements ITreeContentProvider {
 
 202     private Object[] NO_CLASS = new Object[] { new NoClassElement() };
 
 204     private ElementChangedListener fListener;
 
 206     protected boolean matches(IJavaElement element) {
 
 207       if (element.getElementType() == IJavaElement.METHOD) {
 
 208         String name = element.getElementName();
 
 209         return (name != null && name.indexOf('<') >= 0);
 
 214     protected IJavaElement[] filter(IJavaElement[] children) {
 
 215       boolean initializers = false;
 
 216       for (int i = 0; i < children.length; i++) {
 
 217         if (matches(children[i])) {
 
 226       Vector v = new Vector();
 
 227       for (int i = 0; i < children.length; i++) {
 
 228         if (matches(children[i]))
 
 230         v.addElement(children[i]);
 
 233       IJavaElement[] result = new IJavaElement[v.size()];
 
 238     public Object[] getChildren(Object parent) {
 
 239       if (parent instanceof IParent) {
 
 240         IParent c = (IParent) parent;
 
 242           return filter(c.getChildren());
 
 243         } catch (JavaModelException x) {
 
 244           PHPeclipsePlugin.log(x);
 
 250     public Object[] getElements(Object parent) {
 
 251       if (fTopLevelTypeOnly) {
 
 252         if (parent instanceof ICompilationUnit) {
 
 254             IType type = getMainType((ICompilationUnit) parent);
 
 255             return type != null ? type.getChildren() : NO_CLASS;
 
 256           } catch (JavaModelException e) {
 
 257             PHPeclipsePlugin.log(e);
 
 260         //                                              else if (parent instanceof IClassFile) {
 
 262         //                                                              IType type= getMainType((IClassFile) parent);
 
 263         //                                                              return type != null ? type.getChildren() : NO_CLASS;
 
 264         //                                                      } catch (JavaModelException e) {
 
 265         //                                                              JavaPlugin.log(e);
 
 269       return getChildren(parent);
 
 272     public Object getParent(Object child) {
 
 273       if (child instanceof IJavaElement) {
 
 274         IJavaElement e = (IJavaElement) child;
 
 275         return e.getParent();
 
 280     public boolean hasChildren(Object parent) {
 
 281       if (parent instanceof IParent) {
 
 282         IParent c = (IParent) parent;
 
 284           IJavaElement[] children = filter(c.getChildren());
 
 285           return (children != null && children.length > 0);
 
 286         } catch (JavaModelException x) {
 
 287           PHPeclipsePlugin.log(x);
 
 293     public boolean isDeleted(Object o) {
 
 297     public void dispose() {
 
 298       if (fListener != null) {
 
 299         JavaCore.removeElementChangedListener(fListener);
 
 305      * @see IContentProvider#inputChanged(Viewer, Object, Object)
 
 307     public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
 
 308       boolean isCU = (newInput instanceof ICompilationUnit);
 
 310       if (isCU && fListener == null) {
 
 311         fListener = new ElementChangedListener();
 
 312         JavaCore.addElementChangedListener(fListener);
 
 313       } else if (!isCU && fListener != null) {
 
 314         JavaCore.removeElementChangedListener(fListener);
 
 320   class JavaOutlineViewer extends TreeViewer {
 
 323      * Indicates an item which has been reused. At the point of its reuse it has been expanded. This field is used to communicate
 
 324      * between <code>internalExpandToLevel</code> and <code>reuseTreeItem</code>.
 
 326     private Item fReusedExpandedItem;
 
 328     private boolean fReorderedMembers;
 
 329     private boolean fForceFireSelectionChanged;
 
 331     public JavaOutlineViewer(Tree tree) {
 
 333       setAutoExpandLevel(ALL_LEVELS);
 
 337      * Investigates the given element change event and if affected incrementally updates the outline.
 
 340          * Investigates the given element change event and if affected
 
 341          * incrementally updates the Java outline.
 
 343          * @param delta the Java element delta used to reconcile the Java outline
 
 345         public void reconcile(IJavaElementDelta delta) {
 
 346                 fReorderedMembers= false;
 
 347                 fForceFireSelectionChanged= false;
 
 348                 if (getSorter() == null) {
 
 349                         if (fTopLevelTypeOnly
 
 350                                 && delta.getElement() instanceof IType
 
 351                                 && (delta.getKind() & IJavaElementDelta.ADDED) != 0)
 
 356                                 Widget w= findItem(fInput);
 
 357                                 if (w != null && !w.isDisposed())
 
 359                                 if (fForceFireSelectionChanged)
 
 360                                         fireSelectionChanged(new SelectionChangedEvent(getSite().getSelectionProvider(), this.getSelection()));
 
 361                                 if (fReorderedMembers) {
 
 363                                         fReorderedMembers= false;
 
 371 //    public void reconcile(IJavaElementDelta delta) {
 
 372 //      fReorderedMembers = false;
 
 373 //      if (getSorter() == null) {
 
 374 //        if (fTopLevelTypeOnly && delta.getElement() instanceof IType && (delta.getKind() & IJavaElementDelta.ADDED) != 0) {
 
 378 //          Widget w = findItem(fInput);
 
 379 //          if (w != null && !w.isDisposed())
 
 381 //          if (fReorderedMembers) {
 
 383 //            fReorderedMembers = false;
 
 393      * @see TreeViewer#internalExpandToLevel
 
 395     protected void internalExpandToLevel(Widget node, int level) {
 
 396       if (node instanceof Item) {
 
 397         Item i = (Item) node;
 
 398         if (i.getData() instanceof IJavaElement) {
 
 399           IJavaElement je = (IJavaElement) i.getData();
 
 400           if (je.getElementType() == IJavaElement.IMPORT_CONTAINER || isInnerType(je)) {
 
 401             if (i != fReusedExpandedItem) {
 
 402               setExpanded(i, false);
 
 408       super.internalExpandToLevel(node, level);
 
 411     protected void reuseTreeItem(Item item, Object element) {
 
 414       Item[] c = getChildren(item);
 
 415       if (c != null && c.length > 0) {
 
 417         if (getExpanded(item))
 
 418           fReusedExpandedItem = item;
 
 420         for (int k = 0; k < c.length; k++) {
 
 421           if (c[k].getData() != null)
 
 427       updateItem(item, element);
 
 428       updatePlus(item, element);
 
 429       internalExpandToLevel(item, ALL_LEVELS);
 
 431       fReusedExpandedItem = null;
 
 432       fForceFireSelectionChanged= true;
 
 435     protected boolean mustUpdateParent(IJavaElementDelta delta, IJavaElement element) {
 
 436 //      if (element instanceof IMethod) {
 
 437 //        if ((delta.getKind() & IJavaElementDelta.ADDED) != 0) {
 
 439 //            return ((IMethod) element).isMainMethod();
 
 440 //          } catch (JavaModelException e) {
 
 441 //            PHPeclipsePlugin.log(e.getStatus());
 
 444 //        return "main".equals(element.getElementName()); //$NON-NLS-1$
 
 449          * @see org.eclipse.jface.viewers.AbstractTreeViewer#isExpandable(java.lang.Object)
 
 451         public boolean isExpandable(Object element) {
 
 453                         return getFilteredChildren(element).length > 0;
 
 455                 return super.isExpandable(element);
 
 457     protected ISourceRange getSourceRange(IJavaElement element) throws JavaModelException {
 
 458       if (element instanceof IMember)// && !(element instanceof IInitializer))
 
 459         return ((IMember) element).getNameRange();
 
 460       if (element instanceof ISourceReference)
 
 461         return ((ISourceReference) element).getSourceRange();
 
 465     protected boolean overlaps(ISourceRange range, int start, int end) {
 
 466       return start <= (range.getOffset() + range.getLength() - 1) && range.getOffset() <= end;
 
 469     protected boolean filtered(IJavaElement parent, IJavaElement child) {
 
 471       Object[] result = new Object[] { child };
 
 472       ViewerFilter[] filters = getFilters();
 
 473       for (int i = 0; i < filters.length; i++) {
 
 474         result = filters[i].filter(this, parent, result);
 
 475         if (result.length == 0)
 
 482     protected void update(Widget w, IJavaElementDelta delta) {
 
 486       IJavaElement parent = delta.getElement();
 
 487       IJavaElementDelta[] affected = delta.getAffectedChildren();
 
 488       Item[] children = getChildren(w);
 
 490       boolean doUpdateParent = false;
 
 491       boolean doUpdateParentsPlus = false;
 
 493       Vector deletions = new Vector();
 
 494       Vector additions = new Vector();
 
 496       for (int i = 0; i < affected.length; i++) {
 
 497         IJavaElementDelta affectedDelta = affected[i];
 
 498         IJavaElement affectedElement = affectedDelta.getElement();
 
 499         int status = affected[i].getKind();
 
 501         // find tree item with affected element
 
 503         for (j = 0; j < children.length; j++)
 
 504           if (affectedElement.equals(children[j].getData()))
 
 507         if (j == children.length) {
 
 508           //        remove from collapsed parent
 
 509           if ((status & IJavaElementDelta.REMOVED) != 0) {
 
 510             doUpdateParentsPlus = true;
 
 514           if ((status & IJavaElementDelta.CHANGED) != 0 && (affectedDelta.getFlags() & IJavaElementDelta.F_MODIFIERS) != 0
 
 515               && !filtered(parent, affectedElement)) {
 
 516             additions.addElement(affectedDelta);
 
 524         if ((status & IJavaElementDelta.REMOVED) != 0) {
 
 525           deletions.addElement(item);
 
 526           doUpdateParent = doUpdateParent || mustUpdateParent(affectedDelta, affectedElement);
 
 529         } else if ((status & IJavaElementDelta.CHANGED) != 0) {
 
 530           int change = affectedDelta.getFlags();
 
 531           doUpdateParent = doUpdateParent || mustUpdateParent(affectedDelta, affectedElement);
 
 533           if ((change & IJavaElementDelta.F_MODIFIERS) != 0) {
 
 534             if (filtered(parent, affectedElement))
 
 535               deletions.addElement(item);
 
 537               updateItem(item, affectedElement);
 
 540           if ((change & IJavaElementDelta.F_CONTENT) != 0)
 
 541             updateItem(item, affectedElement);
 
 543           if ((change & IJavaElementDelta.F_CHILDREN) != 0)
 
 544             update(item, affectedDelta);
 
 546           if ((change & IJavaElementDelta.F_REORDER) != 0)
 
 547             fReorderedMembers = true;
 
 551       // find all elements to add
 
 552       IJavaElementDelta[] add = delta.getAddedChildren();
 
 553       if (additions.size() > 0) {
 
 554         IJavaElementDelta[] tmp = new IJavaElementDelta[add.length + additions.size()];
 
 555         System.arraycopy(add, 0, tmp, 0, add.length);
 
 556         for (int i = 0; i < additions.size(); i++)
 
 557           tmp[i + add.length] = (IJavaElementDelta) additions.elementAt(i);
 
 561       // add at the right position
 
 562       go2: for (int i = 0; i < add.length; i++) {
 
 566           IJavaElement e = add[i].getElement();
 
 567           if (filtered(parent, e))
 
 570           doUpdateParent = doUpdateParent || mustUpdateParent(add[i], e);
 
 571           ISourceRange rng = getSourceRange(e);
 
 572           int start = rng.getOffset();
 
 573           int end = start + rng.getLength() - 1;
 
 577           children = getChildren(w);
 
 579           for (int j = 0; j < children.length; j++) {
 
 581             IJavaElement r = (IJavaElement) item.getData();
 
 584               // parent node collapsed and not be opened before -> do nothing
 
 589               rng = getSourceRange(r);
 
 590               if (overlaps(rng, start, end)) {
 
 592                 // be tolerant if the delta is not correct, or if
 
 593                 // the tree has been updated other than by a delta
 
 594                 reuseTreeItem(item, e);
 
 597               } else if (rng.getOffset() > start) {
 
 599                 if (last != null && deletions.contains(last)) {
 
 601                   deletions.removeElement(last);
 
 602                   reuseTreeItem(last, (Object) e);
 
 605                   createTreeItem(w, (Object) e, j);
 
 610             } catch (JavaModelException x) {
 
 611               // stumbled over deleted element
 
 617           // add at the end of the list
 
 618           if (last != null && deletions.contains(last)) {
 
 620             deletions.removeElement(last);
 
 621             reuseTreeItem(last, e);
 
 624             createTreeItem(w, e, -1);
 
 627         } catch (JavaModelException x) {
 
 628           // the element to be added is not present -> don't add it
 
 632       // remove items which haven't been reused
 
 633       Enumeration e = deletions.elements();
 
 634       while (e.hasMoreElements()) {
 
 635         item = (Item) e.nextElement();
 
 641         updateItem(w, delta.getElement());
 
 642       if (!doUpdateParent && doUpdateParentsPlus && w instanceof Item)
 
 643         updatePlus((Item) w, delta.getElement());
 
 647      * @see ContentViewer#handleLabelProviderChanged(LabelProviderChangedEvent)
 
 649     protected void handleLabelProviderChanged(LabelProviderChangedEvent event) {
 
 650       Object input = getInput();
 
 651       if (event instanceof ProblemsLabelChangedEvent) {
 
 652         ProblemsLabelChangedEvent e = (ProblemsLabelChangedEvent) event;
 
 653         if (e.isMarkerChange() && input instanceof ICompilationUnit) {
 
 654           return; // marker changes can be ignored
 
 657       // look if the underlying resource changed
 
 658       Object[] changed = event.getElements();
 
 659       if (changed != null) {
 
 660         IResource resource = getUnderlyingResource();
 
 661         if (resource != null) {
 
 662           for (int i = 0; i < changed.length; i++) {
 
 663             if (changed[i] != null && changed[i].equals(resource)) {
 
 664               // change event to a full refresh
 
 665               event = new LabelProviderChangedEvent((IBaseLabelProvider) event.getSource());
 
 671       super.handleLabelProviderChanged(event);
 
 674     private IResource getUnderlyingResource() {
 
 675       Object input = getInput();
 
 676       if (input instanceof ICompilationUnit) {
 
 677         ICompilationUnit cu = (ICompilationUnit) input;
 
 678         if (cu.isWorkingCopy()) {
 
 679           return cu.getOriginalElement().getResource();
 
 681           return cu.getResource();
 
 684       //                                        else if (input instanceof IClassFile) {
 
 685       //                                                return ((IClassFile) input).getResource();
 
 692   class LexicalSortingAction extends Action {
 
 694     private JavaElementSorter fSorter = new JavaElementSorter();
 
 696     public LexicalSortingAction() {
 
 698       //                                        WorkbenchHelp.setHelp(this, IJavaHelpContextIds.LEXICAL_SORTING_OUTLINE_ACTION);
 
 699       setText(PHPEditorMessages.getString("JavaOutlinePage.Sort.label")); //$NON-NLS-1$
 
 700       PHPUiImages.setLocalImageDescriptors(this, "alphab_sort_co.gif"); //$NON-NLS-1$
 
 701       setToolTipText(PHPEditorMessages.getString("JavaOutlinePage.Sort.tooltip")); //$NON-NLS-1$
 
 702       setDescription(PHPEditorMessages.getString("JavaOutlinePage.Sort.description")); //$NON-NLS-1$
 
 704       boolean checked = PHPeclipsePlugin.getDefault().getPreferenceStore().getBoolean("LexicalSortingAction.isChecked"); //$NON-NLS-1$
 
 705       valueChanged(checked, false);
 
 709       valueChanged(isChecked(), true);
 
 712     private void valueChanged(final boolean on, boolean store) {
 
 714       BusyIndicator.showWhile(fOutlineViewer.getControl().getDisplay(), new Runnable() {
 
 716           fOutlineViewer.setSorter(on ? fSorter : null);
 
 721         PHPeclipsePlugin.getDefault().getPreferenceStore().setValue("LexicalSortingAction.isChecked", on); //$NON-NLS-1$
 
 725   class ClassOnlyAction extends Action {
 
 727     public ClassOnlyAction() {
 
 729       //                                WorkbenchHelp.setHelp(this, IJavaHelpContextIds.GO_INTO_TOP_LEVEL_TYPE_ACTION);
 
 730       setText(PHPEditorMessages.getString("JavaOutlinePage.GoIntoTopLevelType.label")); //$NON-NLS-1$
 
 731       setToolTipText(PHPEditorMessages.getString("JavaOutlinePage.GoIntoTopLevelType.tooltip")); //$NON-NLS-1$
 
 732       setDescription(PHPEditorMessages.getString("JavaOutlinePage.GoIntoTopLevelType.description")); //$NON-NLS-1$
 
 733       PHPUiImages.setLocalImageDescriptors(this, "gointo_toplevel_type.gif"); //$NON-NLS-1$
 
 735       IPreferenceStore preferenceStore = PHPeclipsePlugin.getDefault().getPreferenceStore();
 
 736       boolean showclass = preferenceStore.getBoolean("GoIntoTopLevelTypeAction.isChecked"); //$NON-NLS-1$
 
 737       setTopLevelTypeOnly(showclass);
 
 741      * @see org.eclipse.jface.action.Action#run()
 
 744       setTopLevelTypeOnly(!fTopLevelTypeOnly);
 
 747     private void setTopLevelTypeOnly(boolean show) {
 
 748       fTopLevelTypeOnly = show;
 
 750       fOutlineViewer.refresh(false);
 
 752       IPreferenceStore preferenceStore = PHPeclipsePlugin.getDefault().getPreferenceStore();
 
 753       preferenceStore.setValue("GoIntoTopLevelTypeAction.isChecked", show); //$NON-NLS-1$
 
 758    * This action toggles whether this Java Outline page links its selection to the active editor.
 
 762   public class ToggleLinkingAction extends AbstractToggleLinkingAction {
 
 764     JavaOutlinePage fJavaOutlinePage;
 
 767      * Constructs a new action.
 
 770      *          the Java outline page
 
 772     public ToggleLinkingAction(JavaOutlinePage outlinePage) {
 
 773       boolean isLinkingEnabled = PreferenceConstants.getPreferenceStore().getBoolean(
 
 774           PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE);
 
 775       setChecked(isLinkingEnabled);
 
 776       fJavaOutlinePage = outlinePage;
 
 783       PreferenceConstants.getPreferenceStore().setValue(PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE, isChecked());
 
 784       if (isChecked() && fEditor != null)
 
 785         fEditor.synchronizeOutlinePage(fEditor.computeHighlightRangeSourceReference(), false);
 
 790   /** A flag to show contents of top level type only */
 
 791   private boolean fTopLevelTypeOnly;
 
 793   private IJavaElement fInput;
 
 795   private String fContextMenuID;
 
 799   private JavaOutlineViewer fOutlineViewer;
 
 801   private PHPEditor fEditor;
 
 803   private MemberFilterActionGroup fMemberFilterActionGroup;
 
 805   private ListenerList fSelectionChangedListeners = new ListenerList();
 
 807   private ListenerList fPostSelectionChangedListeners = new ListenerList();
 
 809   private Hashtable fActions = new Hashtable();
 
 811   private TogglePresentationAction fTogglePresentation;
 
 813   private GotoErrorAction fPreviousError;
 
 815   private GotoErrorAction fNextError;
 
 817   private TextEditorAction fShowJavadoc;
 
 819   private TextOperationAction fUndo;
 
 821   private TextOperationAction fRedo;
 
 823   private ToggleLinkingAction fToggleLinkingAction;
 
 825   private CompositeActionGroup fActionGroups;
 
 827   //    private CCPActionGroup fCCPActionGroup;
 
 829   private IPropertyChangeListener fPropertyChangeListener;
 
 831          * Custom filter action group.
 
 834 //  private CustomFiltersActionGroup fCustomFiltersActionGroup;
 
 836   public JavaOutlinePage(String contextMenuID, PHPEditor editor) {
 
 839     Assert.isNotNull(editor);
 
 841     fContextMenuID = contextMenuID;
 
 844     fTogglePresentation = new TogglePresentationAction();
 
 845     fPreviousError = new GotoErrorAction("PreviousError.", false); //$NON-NLS-1$
 
 846     fPreviousError.setImageDescriptor(PHPUiImages.DESC_TOOL_GOTO_PREV_ERROR);
 
 847     fNextError = new GotoErrorAction("NextError.", true); //$NON-NLS-1$
 
 848     fNextError.setImageDescriptor(PHPUiImages.DESC_TOOL_GOTO_NEXT_ERROR);
 
 849     fShowJavadoc = (TextEditorAction) fEditor.getAction("ShowJavaDoc"); //$NON-NLS-1$
 
 850     fUndo = (TextOperationAction) fEditor.getAction(ITextEditorActionConstants.UNDO);
 
 851     fRedo = (TextOperationAction) fEditor.getAction(ITextEditorActionConstants.REDO);
 
 853     fTogglePresentation.setEditor(editor);
 
 854     fPreviousError.setEditor(editor);
 
 855     fNextError.setEditor(editor);
 
 857     fPropertyChangeListener = new IPropertyChangeListener() {
 
 858       public void propertyChange(PropertyChangeEvent event) {
 
 859         doPropertyChange(event);
 
 862     PHPeclipsePlugin.getDefault().getPreferenceStore().addPropertyChangeListener(fPropertyChangeListener);
 
 866    * Returns the primary type of a compilation unit (has the same name as the compilation unit).
 
 868    * @param compilationUnit
 
 869    *          the compilation unit
 
 870    * @return returns the primary type of the compilation unit, or <code>null</code> if is does not have one
 
 872   protected IType getMainType(ICompilationUnit compilationUnit) {
 
 873     String name = compilationUnit.getElementName();
 
 874     int index = name.indexOf('.');
 
 876       name = name.substring(0, index);
 
 877     IType type = compilationUnit.getType(name);
 
 878     return type.exists() ? type : null;
 
 882    * Returns the primary type of a class file.
 
 886    * @return returns the primary type of the class file, or <code>null</code> if is does not have one
 
 888   //    protected IType getMainType(IClassFile classFile) {
 
 890   //                    IType type= classFile.getType();
 
 891   //                    return type != null && type.exists() ? type : null;
 
 892   //            } catch (JavaModelException e) {
 
 897    * (non-Javadoc) Method declared on Page
 
 899   public void init(IPageSite pageSite) {
 
 900     super.init(pageSite);
 
 903   private void doPropertyChange(PropertyChangeEvent event) {
 
 904     if (fOutlineViewer != null) {
 
 905       if (PreferenceConstants.APPEARANCE_MEMBER_SORT_ORDER.equals(event.getProperty())) {
 
 906         fOutlineViewer.refresh(false);
 
 912    * @see ISelectionProvider#addSelectionChangedListener(ISelectionChangedListener)
 
 914   public void addSelectionChangedListener(ISelectionChangedListener listener) {
 
 915     if (fOutlineViewer != null)
 
 916       fOutlineViewer.addPostSelectionChangedListener(listener);
 
 918       fSelectionChangedListeners.add(listener);
 
 922    * @see ISelectionProvider#removeSelectionChangedListener(ISelectionChangedListener)
 
 924   public void removeSelectionChangedListener(ISelectionChangedListener listener) {
 
 925     if (fOutlineViewer != null)
 
 926       fOutlineViewer.removePostSelectionChangedListener(listener);
 
 928       fSelectionChangedListeners.remove(listener);
 
 932    * @see ISelectionProvider#setSelection(ISelection)
 
 934   public void setSelection(ISelection selection) {
 
 935     if (fOutlineViewer != null)
 
 936       fOutlineViewer.setSelection(selection);
 
 940    * @see ISelectionProvider#getSelection()
 
 942   public ISelection getSelection() {
 
 943     if (fOutlineViewer == null)
 
 944       return StructuredSelection.EMPTY;
 
 945     return fOutlineViewer.getSelection();
 
 948   //  private void registerToolbarActions() {
 
 950   //    IToolBarManager toolBarManager = getSite().getActionBars().getToolBarManager();
 
 951   //    if (toolBarManager != null) {
 
 952   //      toolBarManager.add(new ClassOnlyAction());
 
 953   //      toolBarManager.add(new LexicalSortingAction());
 
 955   //      fMemberFilterActionGroup = new MemberFilterActionGroup(fOutlineViewer, "JavaOutlineViewer"); //$NON-NLS-1$
 
 956   //      fMemberFilterActionGroup.contributeToToolBar(toolBarManager);
 
 961   private void registerToolbarActions(IActionBars actionBars) {
 
 963     IToolBarManager toolBarManager = actionBars.getToolBarManager();
 
 964     if (toolBarManager != null) {
 
 965       toolBarManager.add(new LexicalSortingAction());
 
 967       fMemberFilterActionGroup = new MemberFilterActionGroup(fOutlineViewer, "org.eclipse.jdt.ui.JavaOutlinePage"); //$NON-NLS-1$
 
 968       fMemberFilterActionGroup.contributeToToolBar(toolBarManager);
 
 970       //                fCustomFiltersActionGroup.fillActionBars(actionBars);
 
 972       IMenuManager menu = actionBars.getMenuManager();
 
 973       menu.add(new Separator("EndFilterGroup")); //$NON-NLS-1$
 
 975       fToggleLinkingAction = new ToggleLinkingAction(this);
 
 976       menu.add(new ClassOnlyAction());
 
 977       menu.add(fToggleLinkingAction);
 
 982    * @see IPage#createControl
 
 984   public void createControl(Composite parent) {
 
 986     Tree tree = new Tree(parent, SWT.MULTI);
 
 988     AppearanceAwareLabelProvider lprovider = new AppearanceAwareLabelProvider(AppearanceAwareLabelProvider.DEFAULT_TEXTFLAGS
 
 989         | JavaElementLabels.F_APP_TYPE_SIGNATURE, AppearanceAwareLabelProvider.DEFAULT_IMAGEFLAGS);
 
 991     fOutlineViewer = new JavaOutlineViewer(tree);
 
 992     fOutlineViewer.setContentProvider(new ChildrenProvider());
 
 993     fOutlineViewer.setLabelProvider(new DecoratingJavaLabelProvider(lprovider));
 
 995     Object[] listeners = fSelectionChangedListeners.getListeners();
 
 996     for (int i = 0; i < listeners.length; i++) {
 
 997       fSelectionChangedListeners.remove(listeners[i]);
 
 998       fOutlineViewer.addPostSelectionChangedListener((ISelectionChangedListener) listeners[i]);
 
1001     listeners = fPostSelectionChangedListeners.getListeners();
 
1002     for (int i = 0; i < listeners.length; i++) {
 
1003       fPostSelectionChangedListeners.remove(listeners[i]);
 
1004       fOutlineViewer.addPostSelectionChangedListener((ISelectionChangedListener) listeners[i]);
 
1007     MenuManager manager = new MenuManager(fContextMenuID, fContextMenuID);
 
1008     manager.setRemoveAllWhenShown(true);
 
1009     manager.addMenuListener(new IMenuListener() {
 
1010       public void menuAboutToShow(IMenuManager manager) {
 
1011         contextMenuAboutToShow(manager);
 
1014     fMenu = manager.createContextMenu(tree);
 
1015     tree.setMenu(fMenu);
 
1017     IPageSite site = getSite();
 
1018     site.registerContextMenu(PHPeclipsePlugin.getPluginId() + ".outline", manager, fOutlineViewer); //$NON-NLS-1$
 
1019     site.setSelectionProvider(fOutlineViewer);
 
1021     // we must create the groups after we have set the selection provider to the site
 
1022     fActionGroups = new CompositeActionGroup(new ActionGroup[] {
 
1023     //                          new OpenViewActionGroup(this),
 
1024         //                              fCCPActionGroup= new CCPActionGroup(this),
 
1025         new GenerateActionGroup(this) });
 
1026     //                          new RefactorActionGroup(this),
 
1027     //                          new JavaSearchActionGroup(this)});
 
1029     // register global actions
 
1030     IActionBars bars = site.getActionBars();
 
1032     bars.setGlobalActionHandler(ITextEditorActionConstants.UNDO, fUndo);
 
1033     bars.setGlobalActionHandler(ITextEditorActionConstants.REDO, fRedo);
 
1034     bars.setGlobalActionHandler(ITextEditorActionConstants.PREVIOUS, fPreviousError);
 
1035     bars.setGlobalActionHandler(ITextEditorActionConstants.NEXT, fNextError);
 
1036     //          bars.setGlobalActionHandler(PHPdtActionConstants.SHOW_PHP_DOC, fShowJavadoc);
 
1037     bars.setGlobalActionHandler(IJavaEditorActionConstants.TOGGLE_PRESENTATION, fTogglePresentation);
 
1038     // http://dev.eclipse.org/bugs/show_bug.cgi?id=18968
 
1039     bars.setGlobalActionHandler(IJavaEditorActionConstants.PREVIOUS_ERROR, fPreviousError);
 
1040     bars.setGlobalActionHandler(IJavaEditorActionConstants.NEXT_ERROR, fNextError);
 
1042     fActionGroups.fillActionBars(bars);
 
1044     IStatusLineManager statusLineManager = site.getActionBars().getStatusLineManager();
 
1045     if (statusLineManager != null) {
 
1046       StatusBarUpdater updater = new StatusBarUpdater(statusLineManager);
 
1047       fOutlineViewer.addPostSelectionChangedListener(updater);
 
1050     registerToolbarActions(bars);
 
1052     fOutlineViewer.setInput(fInput);
 
1053     //    fOutlineViewer.getControl().addKeyListener(new KeyAdapter() {
 
1054     //      public void keyPressed(KeyEvent e) {
 
1055     //        handleKeyReleased(e);
 
1059     //    initDragAndDrop();
 
1062   public void dispose() {
 
1064     if (fEditor == null)
 
1067     if (fMemberFilterActionGroup != null) {
 
1068       fMemberFilterActionGroup.dispose();
 
1069       fMemberFilterActionGroup = null;
 
1072     fEditor.outlinePageClosed();
 
1075     fSelectionChangedListeners.clear();
 
1076     fSelectionChangedListeners = null;
 
1078     fPostSelectionChangedListeners.clear();
 
1079     fPostSelectionChangedListeners = null;
 
1081     if (fPropertyChangeListener != null) {
 
1082       PHPeclipsePlugin.getDefault().getPreferenceStore().removePropertyChangeListener(fPropertyChangeListener);
 
1083       fPropertyChangeListener = null;
 
1086     if (fMenu != null && !fMenu.isDisposed()) {
 
1091     if (fActionGroups != null)
 
1092       fActionGroups.dispose();
 
1094     fTogglePresentation.setEditor(null);
 
1095     fPreviousError.setEditor(null);
 
1096     fNextError.setEditor(null);
 
1098     fOutlineViewer = null;
 
1103   public Control getControl() {
 
1104     if (fOutlineViewer != null)
 
1105       return fOutlineViewer.getControl();
 
1109   public void setInput(IJavaElement inputElement) {
 
1110     fInput = inputElement;
 
1111     if (fOutlineViewer != null)
 
1112       fOutlineViewer.setInput(fInput);
 
1115   public void select(ISourceReference reference) {
 
1116     if (fOutlineViewer != null) {
 
1118       ISelection s = fOutlineViewer.getSelection();
 
1119       if (s instanceof IStructuredSelection) {
 
1120         IStructuredSelection ss = (IStructuredSelection) s;
 
1121         List elements = ss.toList();
 
1122         if (!elements.contains(reference)) {
 
1123           s = (reference == null ? StructuredSelection.EMPTY : new StructuredSelection(reference));
 
1124           fOutlineViewer.setSelection(s, true);
 
1130   public void setAction(String actionID, IAction action) {
 
1131     Assert.isNotNull(actionID);
 
1133       fActions.remove(actionID);
 
1135       fActions.put(actionID, action);
 
1138   public IAction getAction(String actionID) {
 
1139     Assert.isNotNull(actionID);
 
1140     return (IAction) fActions.get(actionID);
 
1144    * Answer the property defined by key.
 
1146   public Object getAdapter(Class key) {
 
1147     if (key == IShowInSource.class) {
 
1148       return getShowInSource();
 
1150     if (key == IShowInTargetList.class) {
 
1151       return new IShowInTargetList() {
 
1152         public String[] getShowInTargetIds() {
 
1153           return new String[] { JavaUI.ID_PACKAGES };
 
1158     if (key == IShowInTarget.class) {
 
1159       return getShowInTarget();
 
1166    * Convenience method to add the action installed under the given actionID to the specified group of the menu.
 
1168   protected void addAction(IMenuManager menu, String group, String actionID) {
 
1169     IAction action = getAction(actionID);
 
1170     if (action != null) {
 
1171       if (action instanceof IUpdate)
 
1172         ((IUpdate) action).update();
 
1174       if (action.isEnabled()) {
 
1175         IMenuManager subMenu = menu.findMenuUsingPath(group);
 
1176         if (subMenu != null)
 
1177           subMenu.add(action);
 
1179           menu.appendToGroup(group, action);
 
1184   protected void contextMenuAboutToShow(IMenuManager menu) {
 
1186     PHPeclipsePlugin.createStandardGroups(menu);
 
1188     IStructuredSelection selection = (IStructuredSelection) getSelection();
 
1189     fActionGroups.setContext(new ActionContext(selection));
 
1190     fActionGroups.fillContextMenu(menu);
 
1194    * @see Page#setFocus()
 
1196   public void setFocus() {
 
1197     if (fOutlineViewer != null)
 
1198       fOutlineViewer.getControl().setFocus();
 
1202    * Checkes whether a given Java element is an inner type.
 
1204   private boolean isInnerType(IJavaElement element) {
 
1206     if (element.getElementType() == IJavaElement.TYPE) {
 
1207       IJavaElement parent = element.getParent();
 
1208       int type = parent.getElementType();
 
1209       return (type != IJavaElement.COMPILATION_UNIT && type != IJavaElement.CLASS_FILE);
 
1216    * Handles key events in viewer.
 
1218   private void handleKeyReleased(KeyEvent event) {
 
1220     if (event.stateMask != 0)
 
1223     IAction action = null;
 
1224     //          if (event.character == SWT.DEL) {
 
1225     //                  action= fCCPActionGroup.getDeleteAction();
 
1228     if (action != null && action.isEnabled())
 
1233    * Returns the <code>IShowInSource</code> for this view.
 
1235   protected IShowInSource getShowInSource() {
 
1236     return new IShowInSource() {
 
1237       public ShowInContext getShowInContext() {
 
1238         return new ShowInContext(null, getSite().getSelectionProvider().getSelection());
 
1244    * Returns the <code>IShowInTarget</code> for this view.
 
1246   protected IShowInTarget getShowInTarget() {
 
1247     return new IShowInTarget() {
 
1248       public boolean show(ShowInContext context) {
 
1249         ISelection sel = context.getSelection();
 
1250         if (sel instanceof ITextSelection) {
 
1251           ITextSelection tsel = (ITextSelection) sel;
 
1252           int offset = tsel.getOffset();
 
1253           IJavaElement element = fEditor.getElementAt(offset);
 
1254           if (element != null) {
 
1255             setSelection(new StructuredSelection(element));
 
1264   private void initDragAndDrop() {
 
1265     int ops = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
 
1266     Transfer[] transfers = new Transfer[] { LocalSelectionTransfer.getInstance() };
 
1269     //          TransferDropTargetListener[] dropListeners= new TransferDropTargetListener[] {
 
1270     //                  new SelectionTransferDropAdapter(fOutlineViewer)
 
1272     //          fOutlineViewer.addDropSupport(ops | DND.DROP_DEFAULT, transfers, new DelegatingDropAdapter(dropListeners));
 
1275     TransferDragSourceListener[] dragListeners = new TransferDragSourceListener[] { new SelectionTransferDragAdapter(fOutlineViewer) };
 
1276     fOutlineViewer.addDragSupport(ops, transfers, new JdtViewerDragAdapter(fOutlineViewer, dragListeners));
 
1280    * @see org.eclipse.jface.text.IPostSelectionProvider#addPostSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
 
1282   public void addPostSelectionChangedListener(ISelectionChangedListener listener) {
 
1283     if (fOutlineViewer != null)
 
1284       fOutlineViewer.addPostSelectionChangedListener(listener);
 
1286       fPostSelectionChangedListeners.add(listener);
 
1290    * @see org.eclipse.jface.text.IPostSelectionProvider#removePostSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
 
1292   public void removePostSelectionChangedListener(ISelectionChangedListener listener) {
 
1293     if (fOutlineViewer != null)
 
1294       fOutlineViewer.removePostSelectionChangedListener(listener);
 
1296       fPostSelectionChangedListeners.remove(listener);