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
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.ResourceBundle;
17 import java.util.Vector;
19 import net.sourceforge.phpdt.core.ElementChangedEvent;
20 import net.sourceforge.phpdt.core.ICompilationUnit;
21 import net.sourceforge.phpdt.core.IElementChangedListener;
22 import net.sourceforge.phpdt.core.IField;
23 import net.sourceforge.phpdt.core.IJavaElement;
24 import net.sourceforge.phpdt.core.IJavaElementDelta;
25 import net.sourceforge.phpdt.core.IMember;
26 import net.sourceforge.phpdt.core.IMethod;
27 import net.sourceforge.phpdt.core.IParent;
28 import net.sourceforge.phpdt.core.ISourceRange;
29 import net.sourceforge.phpdt.core.ISourceReference;
30 import net.sourceforge.phpdt.core.IType;
31 import net.sourceforge.phpdt.core.JavaCore;
32 import net.sourceforge.phpdt.core.JavaModelException;
33 import net.sourceforge.phpdt.internal.corext.util.JavaModelUtil;
34 import net.sourceforge.phpdt.internal.ui.IJavaHelpContextIds;
35 import net.sourceforge.phpdt.internal.ui.PHPUiImages;
36 import net.sourceforge.phpdt.internal.ui.actions.AbstractToggleLinkingAction;
37 import net.sourceforge.phpdt.internal.ui.actions.CompositeActionGroup;
38 import net.sourceforge.phpdt.internal.ui.preferences.MembersOrderPreferenceCache;
39 import net.sourceforge.phpdt.internal.ui.viewsupport.AppearanceAwareLabelProvider;
40 import net.sourceforge.phpdt.internal.ui.viewsupport.DecoratingJavaLabelProvider;
41 import net.sourceforge.phpdt.internal.ui.viewsupport.JavaElementLabels;
42 import net.sourceforge.phpdt.internal.ui.viewsupport.StatusBarUpdater;
43 import net.sourceforge.phpdt.ui.JavaElementSorter;
44 import net.sourceforge.phpdt.ui.JavaUI;
45 import net.sourceforge.phpdt.ui.PreferenceConstants;
46 import net.sourceforge.phpdt.ui.ProblemsLabelDecorator.ProblemsLabelChangedEvent;
47 import net.sourceforge.phpdt.ui.actions.CustomFiltersActionGroup;
48 import net.sourceforge.phpdt.ui.actions.GenerateActionGroup;
49 import net.sourceforge.phpdt.ui.actions.MemberFilterActionGroup;
50 import net.sourceforge.phpdt.ui.actions.PHPdtActionConstants;
51 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
52 import net.sourceforge.phpeclipse.ui.WebUI;
54 import org.eclipse.core.resources.IResource;
55 import org.eclipse.core.runtime.IAdaptable;
56 import org.eclipse.core.runtime.ListenerList;
57 import org.eclipse.jface.action.Action;
58 import org.eclipse.jface.action.IAction;
59 import org.eclipse.jface.action.IMenuListener;
60 import org.eclipse.jface.action.IMenuManager;
61 import org.eclipse.jface.action.IStatusLineManager;
62 import org.eclipse.jface.action.IToolBarManager;
63 import org.eclipse.jface.action.MenuManager;
64 import org.eclipse.jface.action.Separator;
65 import org.eclipse.jface.preference.IPreferenceStore;
67 //import org.eclipse.jface.text.Assert;
68 import org.eclipse.core.runtime.Assert;
69 import org.eclipse.jface.text.ITextSelection;
70 import org.eclipse.jface.util.IPropertyChangeListener;
71 import org.eclipse.jface.util.PropertyChangeEvent;
72 import org.eclipse.jface.viewers.IBaseLabelProvider;
73 import org.eclipse.jface.viewers.IPostSelectionProvider;
74 import org.eclipse.jface.viewers.ISelection;
75 import org.eclipse.jface.viewers.ISelectionChangedListener;
76 import org.eclipse.jface.viewers.IStructuredSelection;
77 import org.eclipse.jface.viewers.ITreeContentProvider;
78 import org.eclipse.jface.viewers.LabelProviderChangedEvent;
79 import org.eclipse.jface.viewers.SelectionChangedEvent;
80 import org.eclipse.jface.viewers.StructuredSelection;
81 import org.eclipse.jface.viewers.TreeViewer;
82 import org.eclipse.jface.viewers.Viewer;
83 import org.eclipse.jface.viewers.ViewerFilter;
84 import org.eclipse.swt.SWT;
85 import org.eclipse.swt.custom.BusyIndicator;
86 import org.eclipse.swt.dnd.DND;
87 import org.eclipse.swt.dnd.Transfer;
88 import org.eclipse.swt.widgets.Composite;
89 import org.eclipse.swt.widgets.Control;
90 import org.eclipse.swt.widgets.Display;
91 import org.eclipse.swt.widgets.Item;
92 import org.eclipse.swt.widgets.Menu;
93 import org.eclipse.swt.widgets.Tree;
94 import org.eclipse.swt.widgets.Widget;
95 import org.eclipse.ui.IActionBars;
96 import org.eclipse.ui.PlatformUI;
97 import org.eclipse.ui.actions.ActionContext;
98 import org.eclipse.ui.actions.ActionFactory;
99 import org.eclipse.ui.actions.ActionGroup;
100 import org.eclipse.ui.model.IWorkbenchAdapter;
101 import org.eclipse.ui.model.WorkbenchAdapter;
102 import org.eclipse.ui.part.IPageSite;
103 import org.eclipse.ui.part.IShowInSource;
104 import org.eclipse.ui.part.IShowInTarget;
105 import org.eclipse.ui.part.IShowInTargetList;
106 import org.eclipse.ui.part.Page;
107 import org.eclipse.ui.part.ShowInContext;
108 import org.eclipse.ui.texteditor.GotoAnnotationAction;
109 import org.eclipse.ui.texteditor.ITextEditorActionConstants;
110 import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
111 import org.eclipse.ui.texteditor.IUpdate;
112 import org.eclipse.ui.texteditor.TextEditorAction;
113 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
114 import org.eclipse.ui.views.navigator.LocalSelectionTransfer;
117 * The content outline page of the Java editor. The viewer implements a
118 * proprietary update mechanism based on Java model deltas. It does not react on
119 * domain changes. It is specified to show the content of ICompilationUnits and
120 * IClassFiles. Publishes its context menu under
121 * <code>PHPeclipsePlugin.getDefault().getPluginId() + ".outline"</code>.
123 public class JavaOutlinePage extends Page implements IContentOutlinePage,
124 IAdaptable, IPostSelectionProvider {
126 static Object[] NO_CHILDREN = new Object[0];
129 * The element change listener of the java outline viewer.
131 * @see IElementChangedListener
133 class ElementChangedListener implements IElementChangedListener {
135 public void elementChanged(final ElementChangedEvent e) {
137 if (getControl() == null)
140 Display d = getControl().getDisplay();
142 d.asyncExec(new Runnable() {
144 ICompilationUnit cu = (ICompilationUnit) fInput;
145 IJavaElement base = cu;
146 // if (fTopLevelTypeOnly) {
147 // base= getMainType(cu);
148 // if (base == null) {
149 if (fOutlineViewer != null)
150 fOutlineViewer.refresh(true);
154 // IJavaElementDelta delta= findElement(base,
156 // if (delta != null && fOutlineViewer != null) {
157 // fOutlineViewer.reconcile(delta);
164 private boolean isPossibleStructuralChange(IJavaElementDelta cuDelta) {
165 if (cuDelta.getKind() != IJavaElementDelta.CHANGED) {
166 return true; // add or remove
168 int flags = cuDelta.getFlags();
169 if ((flags & IJavaElementDelta.F_CHILDREN) != 0) {
172 return (flags & (IJavaElementDelta.F_CONTENT | IJavaElementDelta.F_FINE_GRAINED)) == IJavaElementDelta.F_CONTENT;
175 protected IJavaElementDelta findElement(IJavaElement unit,
176 IJavaElementDelta delta) {
178 if (delta == null || unit == null)
181 IJavaElement element = delta.getElement();
183 if (unit.equals(element)) {
184 if (isPossibleStructuralChange(delta)) {
190 if (element.getElementType() > IJavaElement.CLASS_FILE)
193 IJavaElementDelta[] children = delta.getAffectedChildren();
194 if (children == null || children.length == 0)
197 for (int i = 0; i < children.length; i++) {
198 IJavaElementDelta d = findElement(unit, children[i]);
207 static class NoClassElement extends WorkbenchAdapter implements IAdaptable {
209 * @see java.lang.Object#toString()
211 public String toString() {
212 return PHPEditorMessages
213 .getString("JavaOutlinePage.error.NoTopLevelType"); //$NON-NLS-1$
217 * @see org.eclipse.core.runtime.IAdaptable#getAdapter(Class)
219 public Object getAdapter(Class clas) {
220 if (clas == IWorkbenchAdapter.class)
227 * Content provider for the children of an ICompilationUnit or an IClassFile
229 * @see ITreeContentProvider
231 class ChildrenProvider implements ITreeContentProvider {
233 private Object[] NO_CLASS = new Object[] { new NoClassElement() };
235 private ElementChangedListener fListener;
237 protected boolean matches(IJavaElement element) {
238 if (element.getElementType() == IJavaElement.METHOD) {
239 String name = element.getElementName();
240 return (name != null && name.indexOf('<') >= 0);
245 protected IJavaElement[] filter(IJavaElement[] children) {
246 boolean initializers = false;
247 for (int i = 0; i < children.length; i++) {
248 if (matches(children[i])) {
257 Vector v = new Vector();
258 for (int i = 0; i < children.length; i++) {
259 if (matches(children[i]))
261 v.addElement(children[i]);
264 IJavaElement[] result = new IJavaElement[v.size()];
269 public Object[] getChildren(Object parent) {
270 if (parent instanceof IParent) {
271 IParent c = (IParent) parent;
273 return filter(c.getChildren());
274 } catch (JavaModelException x) {
275 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=38341
276 // don't log NotExist exceptions as this is a valid case
277 // since we might have been posted and the element
278 // removed in the meantime.
279 if (PHPeclipsePlugin.isDebug() || !x.isDoesNotExist())
280 PHPeclipsePlugin.log(x);
286 public Object[] getElements(Object parent) {
287 if (fTopLevelTypeOnly) {
288 if (parent instanceof ICompilationUnit) {
290 IType type = getMainType((ICompilationUnit) parent);
291 return type != null ? type.getChildren() : NO_CLASS;
292 } catch (JavaModelException e) {
293 PHPeclipsePlugin.log(e);
296 // else if (parent instanceof IClassFile) {
298 // IType type= getMainType((IClassFile) parent);
299 // return type != null ? type.getChildren() : NO_CLASS;
300 // } catch (JavaModelException e) {
301 // PHPeclipsePlugin.log(e);
305 return getChildren(parent);
308 public Object getParent(Object child) {
309 if (child instanceof IJavaElement) {
310 IJavaElement e = (IJavaElement) child;
311 return e.getParent();
316 public boolean hasChildren(Object parent) {
317 if (parent instanceof IParent) {
318 IParent c = (IParent) parent;
320 IJavaElement[] children = filter(c.getChildren());
321 return (children != null && children.length > 0);
322 } catch (JavaModelException x) {
323 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=38341
324 // don't log NotExist exceptions as this is a valid case
325 // since we might have been posted and the element
326 // removed in the meantime.
327 if (PHPeclipsePlugin.isDebug() || !x.isDoesNotExist())
328 PHPeclipsePlugin.log(x);
334 public boolean isDeleted(Object o) {
338 public void dispose() {
339 if (fListener != null) {
340 JavaCore.removeElementChangedListener(fListener);
346 * @see IContentProvider#inputChanged(Viewer, Object, Object)
348 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
349 boolean isCU = (newInput instanceof ICompilationUnit);
351 if (isCU && fListener == null) {
352 fListener = new ElementChangedListener();
353 JavaCore.addElementChangedListener(fListener);
354 } else if (!isCU && fListener != null) {
355 JavaCore.removeElementChangedListener(fListener);
361 class JavaOutlineViewer extends TreeViewer {
364 * Indicates an item which has been reused. At the point of its reuse it
365 * has been expanded. This field is used to communicate between
366 * <code>internalExpandToLevel</code> and <code>reuseTreeItem</code>.
368 private Item fReusedExpandedItem;
370 private boolean fReorderedMembers;
372 private boolean fForceFireSelectionChanged;
374 public JavaOutlineViewer(Tree tree) {
376 setAutoExpandLevel(ALL_LEVELS);
377 setUseHashlookup(true);
381 * Investigates the given element change event and if affected
382 * incrementally updates the Java outline.
385 * the Java element delta used to reconcile the Java outline
387 public void reconcile(IJavaElementDelta delta) {
388 fReorderedMembers = false;
389 fForceFireSelectionChanged = false;
390 if (getSorter() == null) {
391 if (fTopLevelTypeOnly && delta.getElement() instanceof IType
392 && (delta.getKind() & IJavaElementDelta.ADDED) != 0) {
396 Widget w = findItem(fInput);
397 if (w != null && !w.isDisposed())
399 if (fForceFireSelectionChanged)
400 fireSelectionChanged(new SelectionChangedEvent(
401 getSite().getSelectionProvider(), this
403 if (fReorderedMembers) {
405 fReorderedMembers = false;
415 * @see TreeViewer#internalExpandToLevel
417 protected void internalExpandToLevel(Widget node, int level) {
418 if (node instanceof Item) {
419 Item i = (Item) node;
420 if (i.getData() instanceof IJavaElement) {
421 IJavaElement je = (IJavaElement) i.getData();
422 if (je.getElementType() == IJavaElement.IMPORT_CONTAINER
423 || isInnerType(je)) {
424 if (i != fReusedExpandedItem) {
425 setExpanded(i, false);
431 super.internalExpandToLevel(node, level);
434 protected void reuseTreeItem(Item item, Object element) {
437 Item[] c = getChildren(item);
438 if (c != null && c.length > 0) {
440 if (getExpanded(item))
441 fReusedExpandedItem = item;
443 for (int k = 0; k < c.length; k++) {
444 if (c[k].getData() != null)
450 updateItem(item, element);
451 updatePlus(item, element);
452 internalExpandToLevel(item, ALL_LEVELS);
454 fReusedExpandedItem = null;
455 fForceFireSelectionChanged = true;
458 protected boolean mustUpdateParent(IJavaElementDelta delta,
459 IJavaElement element) {
460 if (element instanceof IMethod) {
461 if ((delta.getKind() & IJavaElementDelta.ADDED) != 0) {
463 return ((IMethod) element).isMainMethod();
464 } catch (JavaModelException e) {
465 PHPeclipsePlugin.log(e.getStatus());
468 return "main".equals(element.getElementName()); //$NON-NLS-1$
474 * @see org.eclipse.jface.viewers.AbstractTreeViewer#isExpandable(java.lang.Object)
476 public boolean isExpandable(Object element) {
478 return getFilteredChildren(element).length > 0;
480 return super.isExpandable(element);
483 protected ISourceRange getSourceRange(IJavaElement element)
484 throws JavaModelException {
485 if (element instanceof ISourceReference)
486 return ((ISourceReference) element).getSourceRange();
487 if (element instanceof IMember)// && !(element instanceof
489 return ((IMember) element).getNameRange();
493 protected boolean overlaps(ISourceRange range, int start, int end) {
494 return start <= (range.getOffset() + range.getLength() - 1)
495 && range.getOffset() <= end;
498 protected boolean filtered(IJavaElement parent, IJavaElement child) {
500 Object[] result = new Object[] { child };
501 ViewerFilter[] filters = getFilters();
502 for (int i = 0; i < filters.length; i++) {
503 result = filters[i].filter(this, parent, result);
504 if (result.length == 0)
511 protected void update(Widget w, IJavaElementDelta delta) {
515 IJavaElement parent = delta.getElement();
516 IJavaElementDelta[] affected = delta.getAffectedChildren();
517 Item[] children = getChildren(w);
519 boolean doUpdateParent = false;
520 boolean doUpdateParentsPlus = false;
522 Vector deletions = new Vector();
523 Vector additions = new Vector();
525 for (int i = 0; i < affected.length; i++) {
526 IJavaElementDelta affectedDelta = affected[i];
527 IJavaElement affectedElement = affectedDelta.getElement();
528 int status = affected[i].getKind();
530 // find tree item with affected element
532 for (j = 0; j < children.length; j++)
533 if (affectedElement.equals(children[j].getData()))
536 if (j == children.length) {
537 // remove from collapsed parent
538 if ((status & IJavaElementDelta.REMOVED) != 0) {
539 doUpdateParentsPlus = true;
543 if ((status & IJavaElementDelta.CHANGED) != 0
544 && (affectedDelta.getFlags() & IJavaElementDelta.F_MODIFIERS) != 0
545 && !filtered(parent, affectedElement)) {
546 additions.addElement(affectedDelta);
554 if ((status & IJavaElementDelta.REMOVED) != 0) {
555 deletions.addElement(item);
556 doUpdateParent = doUpdateParent
557 || mustUpdateParent(affectedDelta, affectedElement);
560 } else if ((status & IJavaElementDelta.CHANGED) != 0) {
561 int change = affectedDelta.getFlags();
562 doUpdateParent = doUpdateParent
563 || mustUpdateParent(affectedDelta, affectedElement);
565 if ((change & IJavaElementDelta.F_MODIFIERS) != 0) {
566 if (filtered(parent, affectedElement))
567 deletions.addElement(item);
569 updateItem(item, affectedElement);
572 if ((change & IJavaElementDelta.F_CONTENT) != 0)
573 updateItem(item, affectedElement);
575 if ((change & IJavaElementDelta.F_CHILDREN) != 0)
576 update(item, affectedDelta);
578 if ((change & IJavaElementDelta.F_REORDER) != 0)
579 fReorderedMembers = true;
583 // find all elements to add
584 IJavaElementDelta[] add = delta.getAddedChildren();
585 if (additions.size() > 0) {
586 IJavaElementDelta[] tmp = new IJavaElementDelta[add.length
588 System.arraycopy(add, 0, tmp, 0, add.length);
589 for (int i = 0; i < additions.size(); i++)
590 tmp[i + add.length] = (IJavaElementDelta) additions
595 // add at the right position
596 go2: for (int i = 0; i < add.length; i++) {
600 IJavaElement e = add[i].getElement();
601 if (filtered(parent, e))
604 doUpdateParent = doUpdateParent
605 || mustUpdateParent(add[i], e);
606 ISourceRange rng = getSourceRange(e);
607 int start = rng.getOffset();
608 int end = start + rng.getLength() - 1;
609 int nameOffset = Integer.MAX_VALUE;
610 if (e instanceof IField) {
611 ISourceRange nameRange = ((IField) e).getNameRange();
612 if (nameRange != null)
613 nameOffset = nameRange.getOffset();
618 children = getChildren(w);
620 for (int j = 0; j < children.length; j++) {
622 IJavaElement r = (IJavaElement) item.getData();
625 // parent node collapsed and not be opened before ->
631 rng = getSourceRange(r);
633 // multi-field declarations always start at
634 // the same offset. They also have the same
635 // end offset if the field sequence is terminated
636 // with a semicolon. If not, the source range
637 // ends behind the identifier / initializer
639 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=51851
640 boolean multiFieldDeclaration = r.getElementType() == IJavaElement.FIELD
641 && e.getElementType() == IJavaElement.FIELD
642 && rng.getOffset() == start;
644 // elements are inserted by occurrence
645 // however, multi-field declarations have
646 // equal source ranges offsets, therefore we
647 // compare name-range offsets.
648 boolean multiFieldOrderBefore = false;
649 if (multiFieldDeclaration) {
650 if (r instanceof IField) {
651 ISourceRange nameRange = ((IField) r)
653 if (nameRange != null) {
654 if (nameRange.getOffset() > nameOffset)
655 multiFieldOrderBefore = true;
660 if (!multiFieldDeclaration
661 && overlaps(rng, start, end)) {
663 // be tolerant if the delta is not correct, or
665 // the tree has been updated other than by a
667 reuseTreeItem(item, e);
670 } else if (multiFieldOrderBefore
671 || rng.getOffset() > start) {
673 if (last != null && deletions.contains(last)) {
675 deletions.removeElement(last);
676 reuseTreeItem(last, e);
679 createTreeItem(w, e, j);
684 } catch (JavaModelException x) {
685 // stumbled over deleted element
691 // add at the end of the list
692 if (last != null && deletions.contains(last)) {
694 deletions.removeElement(last);
695 reuseTreeItem(last, e);
698 createTreeItem(w, e, -1);
701 } catch (JavaModelException x) {
702 // the element to be added is not present -> don't add it
706 // remove items which haven't been reused
707 Enumeration e = deletions.elements();
708 while (e.hasMoreElements()) {
709 item = (Item) e.nextElement();
715 updateItem(w, delta.getElement());
716 if (!doUpdateParent && doUpdateParentsPlus && w instanceof Item)
717 updatePlus((Item) w, delta.getElement());
721 * @see ContentViewer#handleLabelProviderChanged(LabelProviderChangedEvent)
723 protected void handleLabelProviderChanged(
724 LabelProviderChangedEvent event) {
725 Object input = getInput();
726 if (event instanceof ProblemsLabelChangedEvent) {
727 ProblemsLabelChangedEvent e = (ProblemsLabelChangedEvent) event;
728 if (e.isMarkerChange() && input instanceof ICompilationUnit) {
729 return; // marker changes can be ignored
732 // look if the underlying resource changed
733 Object[] changed = event.getElements();
734 if (changed != null) {
735 IResource resource = getUnderlyingResource();
736 if (resource != null) {
737 for (int i = 0; i < changed.length; i++) {
738 if (changed[i] != null && changed[i].equals(resource)) {
739 // change event to a full refresh
740 event = new LabelProviderChangedEvent(
741 (IBaseLabelProvider) event.getSource());
747 super.handleLabelProviderChanged(event);
750 private IResource getUnderlyingResource() {
751 Object input = getInput();
752 if (input instanceof ICompilationUnit) {
753 ICompilationUnit cu = (ICompilationUnit) input;
754 cu = JavaModelUtil.toOriginal(cu);
755 return cu.getResource();
757 // else if (input instanceof IClassFile) {
758 // return ((IClassFile) input).getResource();
765 class LexicalSortingAction extends Action {
767 private JavaElementSorter fSorter = new JavaElementSorter();
769 public LexicalSortingAction() {
771 PlatformUI.getWorkbench().getHelpSystem().setHelp(this,
772 IJavaHelpContextIds.LEXICAL_SORTING_OUTLINE_ACTION);
773 setText(PHPEditorMessages.getString("JavaOutlinePage.Sort.label")); //$NON-NLS-1$
774 PHPUiImages.setLocalImageDescriptors(this, "alphab_sort_co.gif"); //$NON-NLS-1$
775 setToolTipText(PHPEditorMessages
776 .getString("JavaOutlinePage.Sort.tooltip")); //$NON-NLS-1$
777 setDescription(PHPEditorMessages
778 .getString("JavaOutlinePage.Sort.description")); //$NON-NLS-1$
780 boolean checked = WebUI.getDefault()
781 .getPreferenceStore().getBoolean(
782 "LexicalSortingAction.isChecked"); //$NON-NLS-1$
783 valueChanged(checked, false);
787 valueChanged(isChecked(), true);
790 private void valueChanged(final boolean on, boolean store) {
792 BusyIndicator.showWhile(fOutlineViewer.getControl().getDisplay(),
795 fOutlineViewer.setSorter(on ? fSorter : null);
800 WebUI.getDefault().getPreferenceStore().setValue(
801 "LexicalSortingAction.isChecked", on); //$NON-NLS-1$
805 class ClassOnlyAction extends Action {
807 public ClassOnlyAction() {
809 PlatformUI.getWorkbench().getHelpSystem().setHelp(this,
810 IJavaHelpContextIds.GO_INTO_TOP_LEVEL_TYPE_ACTION);
811 setText(PHPEditorMessages
812 .getString("JavaOutlinePage.GoIntoTopLevelType.label")); //$NON-NLS-1$
813 setToolTipText(PHPEditorMessages
814 .getString("JavaOutlinePage.GoIntoTopLevelType.tooltip")); //$NON-NLS-1$
815 setDescription(PHPEditorMessages
816 .getString("JavaOutlinePage.GoIntoTopLevelType.description")); //$NON-NLS-1$
817 PHPUiImages.setLocalImageDescriptors(this,
818 "gointo_toplevel_type.gif"); //$NON-NLS-1$
820 IPreferenceStore preferenceStore = WebUI.getDefault()
821 .getPreferenceStore();
822 boolean showclass = preferenceStore
823 .getBoolean("GoIntoTopLevelTypeAction.isChecked"); //$NON-NLS-1$
824 setTopLevelTypeOnly(showclass);
828 * @see org.eclipse.jface.action.Action#run()
831 setTopLevelTypeOnly(!fTopLevelTypeOnly);
834 private void setTopLevelTypeOnly(boolean show) {
835 fTopLevelTypeOnly = show;
837 fOutlineViewer.refresh(false);
839 IPreferenceStore preferenceStore = WebUI.getDefault()
840 .getPreferenceStore();
842 .setValue("GoIntoTopLevelTypeAction.isChecked", show); //$NON-NLS-1$
847 * This action toggles whether this Java Outline page links its selection to
852 public class ToggleLinkingAction extends AbstractToggleLinkingAction {
854 JavaOutlinePage fJavaOutlinePage;
857 * Constructs a new action.
860 * the Java outline page
862 public ToggleLinkingAction(JavaOutlinePage outlinePage) {
863 boolean isLinkingEnabled = PreferenceConstants
864 .getPreferenceStore()
866 PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE);
867 setChecked(isLinkingEnabled);
868 fJavaOutlinePage = outlinePage;
875 PreferenceConstants.getPreferenceStore().setValue(
876 PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE,
878 if (isChecked() && fEditor != null)
879 fEditor.synchronizeOutlinePage(fEditor
880 .computeHighlightRangeSourceReference(), false);
885 /** A flag to show contents of top level type only */
886 private boolean fTopLevelTypeOnly;
888 private IJavaElement fInput;
890 private String fContextMenuID;
894 private JavaOutlineViewer fOutlineViewer;
896 private PHPEditor fEditor;
898 private MemberFilterActionGroup fMemberFilterActionGroup;
900 private ListenerList fSelectionChangedListeners = new ListenerList();
902 private ListenerList fPostSelectionChangedListeners = new ListenerList();
904 private Hashtable fActions = new Hashtable();
906 private TogglePresentationAction fTogglePresentation;
908 private GotoAnnotationAction fPreviousAnnotation;
910 private GotoAnnotationAction fNextAnnotation;
912 private TextEditorAction fShowJavadoc;
914 private IAction fUndo;
916 private IAction fRedo;
918 private ToggleLinkingAction fToggleLinkingAction;
920 private CompositeActionGroup fActionGroups;
922 private IPropertyChangeListener fPropertyChangeListener;
925 * Custom filter action group.
929 private CustomFiltersActionGroup fCustomFiltersActionGroup;
931 public JavaOutlinePage(String contextMenuID, PHPEditor editor) {
934 Assert.isNotNull(editor);
936 fContextMenuID = contextMenuID;
938 fTogglePresentation = new TogglePresentationAction();
939 ResourceBundle bundle = PHPEditorMessages.getResourceBundle();
940 fPreviousAnnotation = new GotoAnnotationAction(bundle,
941 "PreviousAnnotation.", null, false); //$NON-NLS-1$
942 fNextAnnotation = new GotoAnnotationAction(bundle,
943 "NextAnnotation.", null, true); //$NON-NLS-1$
944 fShowJavadoc = (TextEditorAction) fEditor.getAction("ShowJavaDoc"); //$NON-NLS-1$
945 fUndo = fEditor.getAction(ITextEditorActionConstants.UNDO);
946 fRedo = fEditor.getAction(ITextEditorActionConstants.REDO);
948 fTogglePresentation.setEditor(editor);
949 fPreviousAnnotation.setEditor(editor);
950 fNextAnnotation.setEditor(editor);
952 fPropertyChangeListener = new IPropertyChangeListener() {
953 public void propertyChange(PropertyChangeEvent event) {
954 doPropertyChange(event);
957 WebUI.getDefault().getPreferenceStore()
958 .addPropertyChangeListener(fPropertyChangeListener);
962 * Returns the primary type of a compilation unit (has the same name as the
965 * @param compilationUnit
966 * the compilation unit
967 * @return returns the primary type of the compilation unit, or
968 * <code>null</code> if is does not have one
970 protected IType getMainType(ICompilationUnit compilationUnit) {
972 if (compilationUnit == null)
975 String name = compilationUnit.getElementName();
976 int index = name.indexOf('.');
978 name = name.substring(0, index);
979 IType type = compilationUnit.getType(name);
980 return type.exists() ? type : null;
984 * Returns the primary type of a class file.
988 * @return returns the primary type of the class file, or <code>null</code>
989 * if is does not have one
991 // protected IType getMainType(IClassFile classFile) {
993 // IType type= classFile.getType();
994 // return type != null && type.exists() ? type : null;
995 // } catch (JavaModelException e) {
1000 * (non-Javadoc) Method declared on Page
1002 public void init(IPageSite pageSite) {
1003 super.init(pageSite);
1006 private void doPropertyChange(PropertyChangeEvent event) {
1007 if (fOutlineViewer != null) {
1008 if (MembersOrderPreferenceCache.isMemberOrderProperty(event
1010 fOutlineViewer.refresh(false);
1016 * @see ISelectionProvider#addSelectionChangedListener(ISelectionChangedListener)
1018 public void addSelectionChangedListener(ISelectionChangedListener listener) {
1019 if (fOutlineViewer != null)
1020 fOutlineViewer.addSelectionChangedListener(listener);
1022 fSelectionChangedListeners.add(listener);
1026 * @see ISelectionProvider#removeSelectionChangedListener(ISelectionChangedListener)
1028 public void removeSelectionChangedListener(
1029 ISelectionChangedListener listener) {
1030 if (fOutlineViewer != null)
1031 fOutlineViewer.removeSelectionChangedListener(listener);
1033 fSelectionChangedListeners.remove(listener);
1037 * @see ISelectionProvider#setSelection(ISelection)
1039 public void setSelection(ISelection selection) {
1040 if (fOutlineViewer != null)
1041 fOutlineViewer.setSelection(selection);
1045 * @see ISelectionProvider#getSelection()
1047 public ISelection getSelection() {
1048 if (fOutlineViewer == null)
1049 return StructuredSelection.EMPTY;
1050 return fOutlineViewer.getSelection();
1054 * @see org.eclipse.jface.text.IPostSelectionProvider#addPostSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
1056 public void addPostSelectionChangedListener(
1057 ISelectionChangedListener listener) {
1058 if (fOutlineViewer != null)
1059 fOutlineViewer.addPostSelectionChangedListener(listener);
1061 fPostSelectionChangedListeners.add(listener);
1065 * @see org.eclipse.jface.text.IPostSelectionProvider#removePostSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
1067 public void removePostSelectionChangedListener(
1068 ISelectionChangedListener listener) {
1069 if (fOutlineViewer != null)
1070 fOutlineViewer.removePostSelectionChangedListener(listener);
1072 fPostSelectionChangedListeners.remove(listener);
1075 private void registerToolbarActions(IActionBars actionBars) {
1077 IToolBarManager toolBarManager = actionBars.getToolBarManager();
1078 if (toolBarManager != null) {
1079 toolBarManager.add(new LexicalSortingAction());
1081 fMemberFilterActionGroup = new MemberFilterActionGroup(
1083 "net.sourceforge.phpeclipse.JavaOutlinePage"); //$NON-NLS-1$
1084 fMemberFilterActionGroup.contributeToToolBar(toolBarManager);
1086 fCustomFiltersActionGroup.fillActionBars(actionBars);
1088 IMenuManager menu = actionBars.getMenuManager();
1089 menu.add(new Separator("EndFilterGroup")); //$NON-NLS-1$
1091 fToggleLinkingAction = new ToggleLinkingAction(this);
1092 menu.add(new ClassOnlyAction());
1093 menu.add(fToggleLinkingAction);
1098 * @see IPage#createControl
1100 public void createControl(Composite parent) {
1102 Tree tree = new Tree(parent, SWT.MULTI);
1104 AppearanceAwareLabelProvider lprovider = new AppearanceAwareLabelProvider(
1105 AppearanceAwareLabelProvider.DEFAULT_TEXTFLAGS
1106 | JavaElementLabels.F_APP_TYPE_SIGNATURE,
1107 AppearanceAwareLabelProvider.DEFAULT_IMAGEFLAGS);
1109 fOutlineViewer = new JavaOutlineViewer(tree);
1111 fOutlineViewer.setContentProvider(new ChildrenProvider());
1112 fOutlineViewer.setLabelProvider(new DecoratingJavaLabelProvider(
1115 Object[] listeners = fSelectionChangedListeners.getListeners();
1116 for (int i = 0; i < listeners.length; i++) {
1117 fSelectionChangedListeners.remove(listeners[i]);
1119 .addSelectionChangedListener((ISelectionChangedListener) listeners[i]);
1122 listeners = fPostSelectionChangedListeners.getListeners();
1123 for (int i = 0; i < listeners.length; i++) {
1124 fPostSelectionChangedListeners.remove(listeners[i]);
1126 .addPostSelectionChangedListener((ISelectionChangedListener) listeners[i]);
1129 MenuManager manager = new MenuManager(fContextMenuID, fContextMenuID);
1130 manager.setRemoveAllWhenShown(true);
1131 manager.addMenuListener(new IMenuListener() {
1132 public void menuAboutToShow(IMenuManager m) {
1133 contextMenuAboutToShow(m);
1136 fMenu = manager.createContextMenu(tree);
1137 tree.setMenu(fMenu);
1139 IPageSite site = getSite();
1141 .registerContextMenu(PHPeclipsePlugin.getPluginId()
1142 + ".outline", manager, fOutlineViewer); //$NON-NLS-1$
1143 site.setSelectionProvider(fOutlineViewer);
1145 // we must create the groups after we have set the selection provider to
1147 fActionGroups = new CompositeActionGroup(new ActionGroup[] {
1148 // new OpenViewActionGroup(this),
1149 // new CCPActionGroup(this),
1150 new GenerateActionGroup(this) });
1151 // new RefactorActionGroup(this),
1152 // new JavaSearchActionGroup(this)});
1154 // register global actions
1155 IActionBars bars = site.getActionBars();
1157 bars.setGlobalActionHandler(ITextEditorActionConstants.UNDO, fUndo);
1158 bars.setGlobalActionHandler(ITextEditorActionConstants.REDO, fRedo);
1159 bars.setGlobalActionHandler(ActionFactory.PREVIOUS.getId(),
1160 fPreviousAnnotation);
1162 .setGlobalActionHandler(ActionFactory.NEXT.getId(),
1164 bars.setGlobalActionHandler(PHPdtActionConstants.SHOW_JAVA_DOC,
1167 .setGlobalActionHandler(
1168 ITextEditorActionDefinitionIds.TOGGLE_SHOW_SELECTED_ELEMENT_ONLY,
1169 fTogglePresentation);
1170 bars.setGlobalActionHandler(
1171 ITextEditorActionDefinitionIds.GOTO_NEXT_ANNOTATION,
1173 bars.setGlobalActionHandler(
1174 ITextEditorActionDefinitionIds.GOTO_PREVIOUS_ANNOTATION,
1175 fPreviousAnnotation);
1177 fActionGroups.fillActionBars(bars);
1179 IStatusLineManager statusLineManager = bars.getStatusLineManager();
1180 if (statusLineManager != null) {
1181 StatusBarUpdater updater = new StatusBarUpdater(statusLineManager);
1182 fOutlineViewer.addPostSelectionChangedListener(updater);
1184 // Custom filter group
1185 fCustomFiltersActionGroup = new CustomFiltersActionGroup(
1186 "net.sourceforge.phpdt.ui.JavaOutlinePage", fOutlineViewer); //$NON-NLS-1$
1188 registerToolbarActions(bars);
1190 fOutlineViewer.setInput(fInput);
1193 public void dispose() {
1195 if (fEditor == null)
1198 if (fMemberFilterActionGroup != null) {
1199 fMemberFilterActionGroup.dispose();
1200 fMemberFilterActionGroup = null;
1203 if (fCustomFiltersActionGroup != null) {
1204 fCustomFiltersActionGroup.dispose();
1205 fCustomFiltersActionGroup = null;
1208 fEditor.outlinePageClosed();
1211 fSelectionChangedListeners.clear();
1212 fSelectionChangedListeners = null;
1214 fPostSelectionChangedListeners.clear();
1215 fPostSelectionChangedListeners = null;
1217 if (fPropertyChangeListener != null) {
1218 WebUI.getDefault().getPreferenceStore()
1219 .removePropertyChangeListener(fPropertyChangeListener);
1220 fPropertyChangeListener = null;
1223 if (fMenu != null && !fMenu.isDisposed()) {
1228 if (fActionGroups != null)
1229 fActionGroups.dispose();
1231 fTogglePresentation.setEditor(null);
1232 fPreviousAnnotation.setEditor(null);
1233 fNextAnnotation.setEditor(null);
1235 fOutlineViewer = null;
1240 public Control getControl() {
1241 if (fOutlineViewer != null)
1242 return fOutlineViewer.getControl();
1246 public void setInput(IJavaElement inputElement) {
1247 fInput = inputElement;
1248 if (fOutlineViewer != null)
1249 fOutlineViewer.setInput(fInput);
1252 public void select(ISourceReference reference) {
1253 if (fOutlineViewer != null) {
1255 ISelection s = fOutlineViewer.getSelection();
1256 if (s instanceof IStructuredSelection) {
1257 IStructuredSelection ss = (IStructuredSelection) s;
1258 List elements = ss.toList();
1259 if (!elements.contains(reference)) {
1260 s = (reference == null ? StructuredSelection.EMPTY
1261 : new StructuredSelection(reference));
1262 fOutlineViewer.setSelection(s, true);
1268 public void setAction(String actionID, IAction action) {
1269 Assert.isNotNull(actionID);
1271 fActions.remove(actionID);
1273 fActions.put(actionID, action);
1276 public IAction getAction(String actionID) {
1277 Assert.isNotNull(actionID);
1278 return (IAction) fActions.get(actionID);
1282 * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
1284 public Object getAdapter(Class key) {
1285 if (key == IShowInSource.class) {
1286 return getShowInSource();
1288 if (key == IShowInTargetList.class) {
1289 return new IShowInTargetList() {
1290 public String[] getShowInTargetIds() {
1291 return new String[] { JavaUI.ID_PACKAGES };
1296 if (key == IShowInTarget.class) {
1297 return getShowInTarget();
1304 * Convenience method to add the action installed under the given actionID
1305 * to the specified group of the menu.
1310 * the group to which to add the action
1312 * the ID of the new action
1314 protected void addAction(IMenuManager menu, String group, String actionID) {
1315 IAction action = getAction(actionID);
1316 if (action != null) {
1317 if (action instanceof IUpdate)
1318 ((IUpdate) action).update();
1320 if (action.isEnabled()) {
1321 IMenuManager subMenu = menu.findMenuUsingPath(group);
1322 if (subMenu != null)
1323 subMenu.add(action);
1325 menu.appendToGroup(group, action);
1330 protected void contextMenuAboutToShow(IMenuManager menu) {
1332 WebUI.createStandardGroups(menu);
1334 IStructuredSelection selection = (IStructuredSelection) getSelection();
1335 fActionGroups.setContext(new ActionContext(selection));
1336 fActionGroups.fillContextMenu(menu);
1340 * @see Page#setFocus()
1342 public void setFocus() {
1343 if (fOutlineViewer != null)
1344 fOutlineViewer.getControl().setFocus();
1348 * Checks whether a given Java element is an inner type.
1352 * @return <code>true</code> iff the given element is an inner type
1354 private boolean isInnerType(IJavaElement element) {
1356 if (element != null && element.getElementType() == IJavaElement.TYPE) {
1357 IType type = (IType) element;
1359 return type.isMember();
1360 } catch (JavaModelException e) {
1361 IJavaElement parent = type.getParent();
1362 if (parent != null) {
1363 int parentElementType = parent.getElementType();
1364 return (parentElementType != IJavaElement.COMPILATION_UNIT && parentElementType != IJavaElement.CLASS_FILE);
1373 * Returns the <code>IShowInSource</code> for this view.
1375 * @return the {@link IShowInSource}
1377 protected IShowInSource getShowInSource() {
1378 return new IShowInSource() {
1379 public ShowInContext getShowInContext() {
1380 return new ShowInContext(null, getSite().getSelectionProvider()
1387 * Returns the <code>IShowInTarget</code> for this view.
1389 * @return the {@link IShowInTarget}
1391 protected IShowInTarget getShowInTarget() {
1392 return new IShowInTarget() {
1393 public boolean show(ShowInContext context) {
1394 ISelection sel = context.getSelection();
1395 if (sel instanceof ITextSelection) {
1396 ITextSelection tsel = (ITextSelection) sel;
1397 int offset = tsel.getOffset();
1398 IJavaElement element = fEditor.getElementAt(offset);
1399 if (element != null) {
1400 setSelection(new StructuredSelection(element));
1409 private void initDragAndDrop() {
1410 int ops = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
1411 Transfer[] transfers = new Transfer[] { LocalSelectionTransfer
1415 // TransferDropTargetListener[] dropListeners= new
1416 // TransferDropTargetListener[] {
1417 // new SelectionTransferDropAdapter(fOutlineViewer)
1419 // fOutlineViewer.addDropSupport(ops | DND.DROP_DEFAULT, transfers, new
1420 // DelegatingDropAdapter(dropListeners));
1423 // TransferDragSourceListener[] dragListeners= new
1424 // TransferDragSourceListener[] {
1425 // new SelectionTransferDragAdapter(fOutlineViewer)
1427 // fOutlineViewer.addDragSupport(ops, transfers, new
1428 // JdtViewerDragAdapter(fOutlineViewer, dragListeners));