| /******************************************************************************* |
| * Copyright (c) 2000, 2017 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.dltk.internal.ui.editor; |
| |
| import java.util.ArrayList; |
| import java.util.Hashtable; |
| import java.util.List; |
| |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.ListenerList; |
| import org.eclipse.dltk.annotations.NonNull; |
| import org.eclipse.dltk.core.DLTKCore; |
| import org.eclipse.dltk.core.ElementChangedEvent; |
| import org.eclipse.dltk.core.IDLTKLanguageToolkit; |
| import org.eclipse.dltk.core.IElementChangedListener; |
| import org.eclipse.dltk.core.IMember; |
| import org.eclipse.dltk.core.IModelElement; |
| import org.eclipse.dltk.core.IModelElementDelta; |
| import org.eclipse.dltk.core.IParent; |
| import org.eclipse.dltk.core.ISourceModule; |
| import org.eclipse.dltk.core.ISourceReference; |
| import org.eclipse.dltk.core.ModelException; |
| import org.eclipse.dltk.core.ScriptModelUtil; |
| import org.eclipse.dltk.internal.ui.actions.AbstractToggleLinkingAction; |
| import org.eclipse.dltk.internal.ui.actions.CompositeActionGroup; |
| import org.eclipse.dltk.internal.ui.actions.refactoring.RefactorActionGroup; |
| import org.eclipse.dltk.internal.ui.dnd.DLTKViewerDragSupport; |
| import org.eclipse.dltk.internal.ui.dnd.DLTKViewerDropSupport; |
| import org.eclipse.dltk.ui.DLTKPluginImages; |
| import org.eclipse.dltk.ui.DLTKUIPlugin; |
| import org.eclipse.dltk.ui.IContextMenuConstants; |
| import org.eclipse.dltk.ui.MembersOrderPreferenceCache; |
| import org.eclipse.dltk.ui.ModelElementSorter; |
| import org.eclipse.dltk.ui.PreferenceConstants; |
| import org.eclipse.dltk.ui.ProblemsLabelDecorator.ProblemsLabelChangedEvent; |
| import org.eclipse.dltk.ui.ScriptElementLabels; |
| import org.eclipse.dltk.ui.actions.CustomFiltersActionGroup; |
| import org.eclipse.dltk.ui.actions.MemberFilterActionGroup; |
| import org.eclipse.dltk.ui.actions.OpenViewActionGroup; |
| import org.eclipse.dltk.ui.actions.SearchActionGroup; |
| import org.eclipse.dltk.ui.viewsupport.AppearanceAwareLabelProvider; |
| import org.eclipse.dltk.ui.viewsupport.SourcePositionSorter; |
| import org.eclipse.dltk.ui.viewsupport.StatusBarUpdater; |
| import org.eclipse.dltk.ui.viewsupport.StyledDecoratingModelLabelProvider; |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.action.GroupMarker; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.IStatusLineManager; |
| import org.eclipse.jface.action.IToolBarManager; |
| import org.eclipse.jface.action.MenuManager; |
| import org.eclipse.jface.action.Separator; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.text.ITextSelection; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.jface.viewers.IBaseLabelProvider; |
| import org.eclipse.jface.viewers.ILabelDecorator; |
| import org.eclipse.jface.viewers.IPostSelectionProvider; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.ISelectionChangedListener; |
| import org.eclipse.jface.viewers.ISelectionProvider; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.ITreeContentProvider; |
| import org.eclipse.jface.viewers.LabelProviderChangedEvent; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jface.viewers.TreeViewer; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.BusyIndicator; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Item; |
| import org.eclipse.swt.widgets.Menu; |
| import org.eclipse.swt.widgets.Tree; |
| import org.eclipse.swt.widgets.Widget; |
| import org.eclipse.ui.IActionBars; |
| import org.eclipse.ui.actions.ActionContext; |
| import org.eclipse.ui.actions.ActionGroup; |
| import org.eclipse.ui.navigator.ICommonMenuConstants; |
| import org.eclipse.ui.part.IPageSite; |
| import org.eclipse.ui.part.IShowInSource; |
| import org.eclipse.ui.part.IShowInTarget; |
| import org.eclipse.ui.part.IShowInTargetList; |
| import org.eclipse.ui.part.Page; |
| import org.eclipse.ui.part.ShowInContext; |
| import org.eclipse.ui.texteditor.ITextEditor; |
| import org.eclipse.ui.texteditor.ITextEditorActionConstants; |
| import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; |
| import org.eclipse.ui.texteditor.IUpdate; |
| import org.eclipse.ui.views.contentoutline.IContentOutlinePage; |
| |
| /** |
| * The content outline page of the Java editor. The viewer implements a |
| * proprietary update mechanism based on Java model deltas. It does not react on |
| * domain changes. It is specified to show the content of ICompilationUnits and |
| * IClassFiles. Publishes its context menu under |
| * <code>JavaPlugin.getDefault().getPluginId() + ".outline"</code>. |
| */ |
| public class ScriptOutlinePage extends Page |
| implements IContentOutlinePage, IAdaptable, IPostSelectionProvider { |
| |
| /** |
| * Content provider for the children of an ICompilationUnit or an IClassFile |
| * |
| * @see ITreeContentProvider |
| */ |
| protected class ChildrenProvider implements ITreeContentProvider { |
| |
| // private Object[] NO_CLASS = new Object[] { new NoClassElement() }; |
| private ElementChangedListener fListener; |
| |
| @Override |
| public void dispose() { |
| if (fListener != null) { |
| DLTKCore.removeElementChangedListener(fListener); |
| fListener = null; |
| } |
| } |
| |
| protected IModelElement[] filter(IModelElement[] children) { |
| boolean initializers = false; |
| for (int i = 0; i < children.length; i++) { |
| if (matches(children[i])) { |
| initializers = true; |
| break; |
| } |
| } |
| |
| if (!initializers) { |
| return children; |
| } |
| |
| List<IModelElement> v = new ArrayList<IModelElement>(); |
| for (int i = 0; i < children.length; i++) { |
| if (matches(children[i])) { |
| continue; |
| } |
| v.add(children[i]); |
| } |
| return v.toArray(new IModelElement[v.size()]); |
| } |
| |
| @Override |
| public Object[] getChildren(Object parent) { |
| if (parent instanceof IParent) { |
| IParent c = (IParent) parent; |
| try { |
| return filter(c.getChildren()); |
| } catch (ModelException x) { |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=38341 |
| // don't log NotExist exceptions as this is a valid case |
| // since we might have been posted and the element |
| // removed in the meantime. |
| if (DLTKCore.DEBUG || !x.isDoesNotExist()) { |
| DLTKUIPlugin.log(x); |
| } |
| } |
| } |
| return ScriptOutlinePage.NO_CHILDREN; |
| } |
| |
| @Override |
| public Object[] getElements(Object parent) { |
| return getChildren(parent); |
| } |
| |
| @Override |
| public Object getParent(Object child) { |
| if (child instanceof IModelElement) { |
| IModelElement e = (IModelElement) child; |
| return e.getParent(); |
| } |
| return null; |
| } |
| |
| @Override |
| public boolean hasChildren(Object parent) { |
| if (parent instanceof IParent) { |
| IParent c = (IParent) parent; |
| try { |
| IModelElement[] children = filter(c.getChildren()); |
| return (children != null && children.length > 0); |
| } catch (ModelException x) { |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=38341 |
| // don't log NotExist exceptions as this is a valid case |
| // since we might have been posted and the element |
| // removed in the meantime. |
| if (DLTKUIPlugin.isDebug() || !x.isDoesNotExist()) { |
| DLTKUIPlugin.log(x); |
| } |
| } |
| } |
| return false; |
| } |
| |
| /* |
| * @see IContentProvider#inputChanged(Viewer, Object, Object) |
| */ |
| @Override |
| public void inputChanged(Viewer viewer, Object oldInput, |
| Object newInput) { |
| boolean isCU = (newInput instanceof ISourceModule); |
| |
| if (isCU && fListener == null) { |
| fListener = new ElementChangedListener(); |
| DLTKCore.addElementChangedListener(fListener); |
| } else if (!isCU && fListener != null) { |
| DLTKCore.removeElementChangedListener(fListener); |
| fListener = null; |
| } |
| } |
| |
| protected boolean matches(IModelElement element) { |
| if (element.getElementType() == IModelElement.METHOD) { |
| String name = element.getElementName(); |
| return (name != null && name.indexOf('<') >= 0); |
| } |
| return false; |
| } |
| } |
| |
| /** |
| * The element change listener of the java outline viewer. |
| * |
| * @see IElementChangedListener |
| */ |
| protected class ElementChangedListener implements IElementChangedListener { |
| |
| @Override |
| public void elementChanged(final ElementChangedEvent e) { |
| |
| if (getControl() == null) { |
| return; |
| } |
| |
| Display d = getControl().getDisplay(); |
| if (d != null) { |
| d.asyncExec(() -> { |
| ISourceModule cu = (ISourceModule) fInput; |
| IModelElement base = cu; |
| |
| IModelElementDelta delta = findElement(base, e.getDelta()); |
| if (delta != null && fOutlineViewer != null) { |
| fOutlineViewer.reconcile(delta); |
| } |
| }); |
| } |
| } |
| |
| protected IModelElementDelta findElement(IModelElement unit, |
| IModelElementDelta delta) { |
| |
| if (delta == null || unit == null) { |
| return null; |
| } |
| |
| IModelElement element = delta.getElement(); |
| |
| if (unit.equals(element)) { |
| if (isPossibleStructuralChange(delta)) { |
| return delta; |
| } |
| return null; |
| } |
| |
| if (element.getElementType() > IModelElement.SOURCE_MODULE) { |
| return null; |
| } |
| |
| IModelElementDelta[] children = delta.getAffectedChildren(); |
| if (children == null || children.length == 0) { |
| return null; |
| } |
| |
| for (int i = 0; i < children.length; i++) { |
| IModelElementDelta d = findElement(unit, children[i]); |
| if (d != null) { |
| return d; |
| } |
| } |
| |
| return null; |
| } |
| |
| private boolean isPossibleStructuralChange(IModelElementDelta cuDelta) { |
| if (cuDelta.getKind() != IModelElementDelta.CHANGED) { |
| return true; // add or remove |
| } |
| int flags = cuDelta.getFlags(); |
| if ((flags & IModelElementDelta.F_CHILDREN) != 0) { |
| return true; |
| } |
| return (flags & (IModelElementDelta.F_CONTENT |
| | IModelElementDelta.F_FINE_GRAINED)) == IModelElementDelta.F_CONTENT; |
| } |
| } |
| |
| /** |
| * Empty selection provider. |
| * |
| * @since 3.2 |
| */ |
| private static final class EmptySelectionProvider |
| implements ISelectionProvider { |
| @Override |
| public void addSelectionChangedListener( |
| ISelectionChangedListener listener) { |
| } |
| |
| @Override |
| public ISelection getSelection() { |
| return StructuredSelection.EMPTY; |
| } |
| |
| @Override |
| public void removeSelectionChangedListener( |
| ISelectionChangedListener listener) { |
| } |
| |
| @Override |
| public void setSelection(ISelection selection) { |
| } |
| } |
| |
| private DLTKViewerDropSupport fDropSupport; |
| |
| /** |
| * The tree viewer used for displaying the outline. |
| * |
| * @see TreeViewer |
| */ |
| protected class ScriptOutlineViewer extends TreeViewer { |
| |
| public ScriptOutlineViewer(Tree tree) { |
| super(tree); |
| setAutoExpandLevel(ALL_LEVELS); |
| setUseHashlookup(true); |
| } |
| |
| private IResource getUnderlyingResource() { |
| Object input = getInput(); |
| if (input instanceof ISourceModule) { |
| ISourceModule cu = (ISourceModule) input; |
| cu = cu.getPrimary(); |
| return cu.getResource(); |
| } /* |
| * else if (input instanceof IClassFile) { return ((IClassFile) |
| * input).getResource(); } |
| */ |
| return null; |
| } |
| |
| @Override |
| protected void handleLabelProviderChanged( |
| LabelProviderChangedEvent event) { |
| Object input = getInput(); |
| if (event instanceof ProblemsLabelChangedEvent) { |
| ProblemsLabelChangedEvent e = (ProblemsLabelChangedEvent) event; |
| if (e.isMarkerChange() && input instanceof ISourceModule) { |
| return; // marker changes can be ignored |
| } |
| } |
| // look if the underlying resource changed |
| Object[] changed = event.getElements(); |
| if (changed != null) { |
| IResource resource = getUnderlyingResource(); |
| if (resource != null) { |
| for (int i = 0; i < changed.length; i++) { |
| if (changed[i] != null && changed[i].equals(resource)) { |
| // change event to a full refresh |
| event = new LabelProviderChangedEvent( |
| (IBaseLabelProvider) event.getSource()); |
| break; |
| } |
| } |
| } |
| } |
| super.handleLabelProviderChanged(event); |
| } |
| |
| @Override |
| protected void internalExpandToLevel(Widget node, int level) { |
| if (node instanceof Item) { |
| Item i = (Item) node; |
| if (i.getData() instanceof IModelElement) { |
| IModelElement je = (IModelElement) i.getData(); |
| if (collapseInitially(je)) { |
| setExpanded(i, false); |
| return; |
| } |
| } |
| } |
| super.internalExpandToLevel(node, level); |
| } |
| |
| @Override |
| public boolean isExpandable(Object element) { |
| if (hasFilters()) { |
| return getFilteredChildren(element).length > 0; |
| } |
| return super.isExpandable(element); |
| } |
| |
| /** |
| * Investigates the given element change event and if affected |
| * incrementally updates the Java outline. |
| * |
| * @param delta |
| * the Java element delta used to reconcile the Java outline |
| */ |
| public void reconcile(IModelElementDelta delta) { |
| refresh(true); |
| } |
| |
| } |
| |
| class LexicalSortingAction extends Action { |
| |
| private static final String LEXICAL_SORTING_ACTION_IS_CHECKED = "LexicalSortingAction.isChecked"; //$NON-NLS-1$ |
| |
| private ModelElementSorter fComparator = new ModelElementSorter(); |
| private SourcePositionSorter fSourcePositonComparator = new SourcePositionSorter(); |
| |
| public LexicalSortingAction() { |
| super(); |
| // PlatformUI.getWorkbench().getHelpSystem().setHelp(this, |
| // IJavaHelpContextIds.LEXICAL_SORTING_OUTLINE_ACTION); |
| setText(DLTKEditorMessages.ScriptOutlinePage_Sort_label); |
| DLTKPluginImages.setLocalImageDescriptors(this, |
| "alphab_sort_co.png"); //$NON-NLS-1$ |
| setToolTipText(DLTKEditorMessages.ScriptOutlinePage_Sort_tooltip); |
| setDescription( |
| DLTKEditorMessages.ScriptOutlinePage_Sort_description); |
| |
| boolean checked = fStore |
| .getBoolean(LEXICAL_SORTING_ACTION_IS_CHECKED); |
| valueChanged(checked, false); |
| } |
| |
| @Override |
| public void run() { |
| valueChanged(isChecked(), true); |
| } |
| |
| private void valueChanged(final boolean on, boolean store) { |
| setChecked(on); |
| BusyIndicator.showWhile(fOutlineViewer.getControl().getDisplay(), |
| () -> { |
| if (on) { |
| fOutlineViewer.setComparator(fComparator); |
| fDropSupport.setFeedbackEnabled(false); |
| } else { |
| fOutlineViewer |
| .setComparator(fSourcePositonComparator); |
| fDropSupport.setFeedbackEnabled(true); |
| } |
| }); |
| |
| if (store) { |
| fStore.setValue(LEXICAL_SORTING_ACTION_IS_CHECKED, on); |
| } |
| } |
| } |
| |
| /** |
| * This action toggles whether this Java Outline page links its selection to |
| * the active editor. |
| * |
| * @since 3.0 |
| */ |
| public class ToggleLinkingAction extends AbstractToggleLinkingAction { |
| |
| ScriptOutlinePage fJavaOutlinePage; |
| |
| /** |
| * Constructs a new action. |
| * |
| * @param outlinePage |
| * the Java outline page |
| */ |
| public ToggleLinkingAction(ScriptOutlinePage outlinePage) { |
| boolean isLinkingEnabled = fStore.getBoolean( |
| PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE); |
| setChecked(isLinkingEnabled); |
| fJavaOutlinePage = outlinePage; |
| } |
| |
| /** |
| * Runs the action. |
| */ |
| @Override |
| public void run() { |
| fStore.setValue( |
| PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE, |
| isChecked()); |
| if (isChecked() && fEditor != null) { |
| fEditor.synchronizeOutlinePage( |
| fEditor.computeHighlightRangeSourceReference(), false); |
| } |
| } |
| |
| } |
| |
| static final Object[] NO_CHILDREN = new Object[0]; |
| |
| /** A flag to show contents of top level type only */ |
| // private boolean fTopLevelTypeOnly; |
| private IModelElement fInput; |
| // private String fContextMenuID; |
| private Menu fMenu; |
| protected ScriptOutlineViewer fOutlineViewer; |
| private IScriptEditor fEditor; |
| protected IPreferenceStore fStore; |
| private MemberFilterActionGroup fMemberFilterActionGroup; |
| |
| private ListenerList fSelectionChangedListeners = new ListenerList( |
| ListenerList.IDENTITY); |
| private ListenerList fPostSelectionChangedListeners = new ListenerList( |
| ListenerList.IDENTITY); |
| private Hashtable<String, IAction> fActions = new Hashtable<String, IAction>(); |
| |
| private TogglePresentationAction fTogglePresentation; |
| |
| private ToggleLinkingAction fToggleLinkingAction; |
| |
| private CompositeActionGroup fActionGroups; |
| |
| private IPropertyChangeListener fPropertyChangeListener; |
| /** |
| * Custom filter action group. |
| * |
| * @since 3.0 |
| */ |
| private CustomFiltersActionGroup fCustomFiltersActionGroup; |
| |
| // /** |
| // * Category filter action group. |
| // * |
| // * @since 3.2 |
| // */ |
| // private CategoryFilterActionGroup fCategoryFilterActionGroup; |
| |
| /** |
| * @since 2.0 |
| */ |
| public ScriptOutlinePage(IScriptEditor editor, IPreferenceStore store) { |
| super(); |
| |
| Assert.isNotNull(editor); |
| |
| // fContextMenuID = "#CompilationUnitOutlinerContext";// contextMenuID; |
| fEditor = editor; |
| fStore = store; |
| |
| if (editor instanceof ITextEditor) { |
| fTogglePresentation = new TogglePresentationAction(); |
| fTogglePresentation.setEditor((ITextEditor) editor); |
| } |
| |
| fPropertyChangeListener = event -> doPropertyChange(event); |
| fStore.addPropertyChangeListener(fPropertyChangeListener); |
| } |
| |
| /** |
| * Convenience method to add the action installed under the given actionID |
| * to the specified group of the menu. |
| * |
| * @param menu |
| * the menu manager |
| * @param group |
| * the group to which to add the action |
| * @param actionID |
| * the ID of the new action |
| */ |
| protected void addAction(IMenuManager menu, String group, String actionID) { |
| IAction action = getAction(actionID); |
| if (action != null) { |
| if (action instanceof IUpdate) { |
| ((IUpdate) action).update(); |
| } |
| |
| if (action.isEnabled()) { |
| IMenuManager subMenu = menu.findMenuUsingPath(group); |
| if (subMenu != null) { |
| subMenu.add(action); |
| } else { |
| menu.appendToGroup(group, action); |
| } |
| } |
| } |
| } |
| |
| /* |
| * @see org.eclipse.jface.text.IPostSelectionProvider# |
| * addPostSelectionChangedListener |
| * (org.eclipse.jface.viewers.ISelectionChangedListener) |
| */ |
| @Override |
| public void addPostSelectionChangedListener( |
| ISelectionChangedListener listener) { |
| if (fOutlineViewer != null) { |
| fOutlineViewer.addPostSelectionChangedListener(listener); |
| } else { |
| fPostSelectionChangedListeners.add(listener); |
| } |
| } |
| |
| /* |
| * @see |
| * ISelectionProvider#addSelectionChangedListener(ISelectionChangedListener) |
| */ |
| @Override |
| public void addSelectionChangedListener( |
| ISelectionChangedListener listener) { |
| if (fOutlineViewer != null) { |
| fOutlineViewer.addSelectionChangedListener(listener); |
| } else { |
| fSelectionChangedListeners.add(listener); |
| } |
| } |
| |
| protected void contextMenuAboutToShow(IMenuManager menu) { |
| |
| // DLTKUIPlugin.createStandardGroups(menu); |
| if (menu.isEmpty()) { |
| // menu.add(new Separator(IContextMenuConstants.GROUP_NEW)); |
| menu.add(new GroupMarker(IContextMenuConstants.GROUP_GOTO)); |
| menu.add(new Separator(IContextMenuConstants.GROUP_OPEN)); |
| menu.add(new GroupMarker(IContextMenuConstants.GROUP_SHOW)); |
| menu.add(new Separator(ICommonMenuConstants.GROUP_EDIT)); |
| menu.add(new Separator(IContextMenuConstants.GROUP_REORGANIZE)); |
| // menu.add(new Separator(IContextMenuConstants.GROUP_GENERATE)); |
| menu.add(new Separator(IContextMenuConstants.GROUP_SEARCH)); |
| // menu.add(new Separator(IContextMenuConstants.GROUP_BUILD)); |
| menu.add(new Separator(IContextMenuConstants.GROUP_ADDITIONS)); |
| // menu.add(new |
| // Separator(IContextMenuConstants.GROUP_VIEWER_SETUP)); |
| menu.add(new Separator(IContextMenuConstants.GROUP_PROPERTIES)); |
| } |
| |
| IStructuredSelection selection = (IStructuredSelection) getSelection(); |
| fActionGroups.setContext(new ActionContext(selection)); |
| fActionGroups.fillContextMenu(menu); |
| } |
| |
| protected ILabelDecorator getLabelDecorator() { |
| return null; |
| } |
| |
| @Override |
| public void createControl(Composite parent) { |
| |
| Tree tree = new Tree(parent, SWT.MULTI); |
| |
| AppearanceAwareLabelProvider lprovider = new AppearanceAwareLabelProvider( |
| AppearanceAwareLabelProvider.DEFAULT_TEXTFLAGS |
| | ScriptElementLabels.F_APP_TYPE_SIGNATURE |
| | ScriptElementLabels.ALL_CATEGORY |
| | ScriptElementLabels.M_APP_RETURNTYPE, |
| AppearanceAwareLabelProvider.DEFAULT_IMAGEFLAGS, fStore); |
| |
| ILabelDecorator ldecorator = getLabelDecorator(); |
| if (ldecorator != null) { |
| lprovider.addLabelDecorator(ldecorator); |
| } |
| |
| fOutlineViewer = new ScriptOutlineViewer(tree); |
| initDragAndDrop(); |
| fOutlineViewer.setContentProvider(new ChildrenProvider()); |
| fOutlineViewer.setLabelProvider( |
| new StyledDecoratingModelLabelProvider(lprovider)); |
| |
| Object[] listeners = fSelectionChangedListeners.getListeners(); |
| for (int i = 0; i < listeners.length; i++) { |
| fSelectionChangedListeners.remove(listeners[i]); |
| fOutlineViewer.addSelectionChangedListener( |
| (ISelectionChangedListener) listeners[i]); |
| } |
| |
| listeners = fPostSelectionChangedListeners.getListeners(); |
| for (int i = 0; i < listeners.length; i++) { |
| fPostSelectionChangedListeners.remove(listeners[i]); |
| fOutlineViewer.addPostSelectionChangedListener( |
| (ISelectionChangedListener) listeners[i]); |
| } |
| |
| MenuManager manager = new MenuManager( |
| DLTKUIPlugin.getPluginId() + ".outline", //$NON-NLS-1$ |
| DLTKUIPlugin.getPluginId() + ".outline"); //$NON-NLS-1$ |
| manager.setRemoveAllWhenShown(true); |
| manager.addMenuListener(m -> contextMenuAboutToShow(m)); |
| fMenu = manager.createContextMenu(tree); |
| tree.setMenu(fMenu); |
| |
| IPageSite site = getSite(); |
| site.registerContextMenu(DLTKUIPlugin.getPluginId() + ".outline", //$NON-NLS-1$ |
| manager, fOutlineViewer); |
| |
| updateSelectionProvider(site); |
| |
| IDLTKLanguageToolkit toolkit = fEditor.getLanguageToolkit(); |
| // we must create the groups after we have set the selection provider to |
| // the site |
| fActionGroups = new CompositeActionGroup( |
| new ActionGroup[] { new OpenViewActionGroup(this), |
| // new CCPActionGroup(this), |
| /* new GenerateActionGroup(this), */ |
| new RefactorActionGroup(this, toolkit), |
| new SearchActionGroup(this, toolkit) }); |
| |
| // register global actions |
| IActionBars actionBars = site.getActionBars(); |
| actionBars.setGlobalActionHandler(ITextEditorActionConstants.UNDO, |
| fEditor.getAction(ITextEditorActionConstants.UNDO)); |
| actionBars.setGlobalActionHandler(ITextEditorActionConstants.REDO, |
| fEditor.getAction(ITextEditorActionConstants.REDO)); |
| |
| IAction action = fEditor.getAction(ITextEditorActionConstants.NEXT); |
| actionBars.setGlobalActionHandler( |
| ITextEditorActionDefinitionIds.GOTO_NEXT_ANNOTATION, action); |
| actionBars.setGlobalActionHandler(ITextEditorActionConstants.NEXT, |
| action); |
| action = fEditor.getAction(ITextEditorActionConstants.PREVIOUS); |
| actionBars.setGlobalActionHandler( |
| ITextEditorActionDefinitionIds.GOTO_PREVIOUS_ANNOTATION, |
| action); |
| actionBars.setGlobalActionHandler(ITextEditorActionConstants.PREVIOUS, |
| action); |
| if (fTogglePresentation != null) { |
| actionBars.setGlobalActionHandler( |
| ITextEditorActionDefinitionIds.TOGGLE_SHOW_SELECTED_ELEMENT_ONLY, |
| fTogglePresentation); |
| } |
| |
| fActionGroups.fillActionBars(actionBars); |
| |
| IStatusLineManager statusLineManager = actionBars |
| .getStatusLineManager(); |
| if (statusLineManager != null) { |
| StatusBarUpdater updater = new StatusBarUpdater(statusLineManager); |
| fOutlineViewer.addPostSelectionChangedListener(updater); |
| } |
| // Custom filter group |
| fCustomFiltersActionGroup = new CustomFiltersActionGroup( |
| "org.eclipse.dltk.ui.ScriptOutlinePage", fOutlineViewer); //$NON-NLS-1$ |
| |
| registerToolbarActions(actionBars); |
| |
| fOutlineViewer.setInput(fInput); |
| } |
| |
| @Override |
| public void dispose() { |
| |
| if (fEditor == null) { |
| return; |
| } |
| |
| if (fMemberFilterActionGroup != null) { |
| fMemberFilterActionGroup.dispose(); |
| fMemberFilterActionGroup = null; |
| } |
| |
| // if (fCategoryFilterActionGroup != null) { |
| // fCategoryFilterActionGroup.dispose(); |
| // fCategoryFilterActionGroup = null; |
| // } |
| |
| if (fCustomFiltersActionGroup != null) { |
| fCustomFiltersActionGroup.dispose(); |
| fCustomFiltersActionGroup = null; |
| } |
| |
| fEditor.outlinePageClosed(); |
| fEditor = null; |
| |
| fSelectionChangedListeners.clear(); |
| fSelectionChangedListeners = null; |
| |
| fPostSelectionChangedListeners.clear(); |
| fPostSelectionChangedListeners = null; |
| |
| if (fPropertyChangeListener != null) { |
| fStore.removePropertyChangeListener(fPropertyChangeListener); |
| fPropertyChangeListener = null; |
| } |
| |
| if (fMenu != null && !fMenu.isDisposed()) { |
| fMenu.dispose(); |
| fMenu = null; |
| } |
| |
| if (fActionGroups != null) { |
| fActionGroups.dispose(); |
| } |
| if (fTogglePresentation != null) { |
| fTogglePresentation.setEditor(null); |
| } |
| |
| fOutlineViewer = null; |
| |
| super.dispose(); |
| } |
| |
| private void doPropertyChange(PropertyChangeEvent event) { |
| if (fOutlineViewer != null) { |
| if (MembersOrderPreferenceCache |
| .isMemberOrderProperty(event.getProperty())) { |
| fOutlineViewer.refresh(false); |
| } |
| } |
| } |
| |
| public IAction getAction(String actionID) { |
| Assert.isNotNull(actionID); |
| return fActions.get(actionID); |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Override |
| public <T> T getAdapter(Class<T> key) { |
| if (key == IShowInSource.class) { |
| return (T) getShowInSource(); |
| } |
| if (key == IShowInTargetList.class) { |
| return (T) (IShowInTargetList) () -> new String[] { |
| DLTKUIPlugin.ID_SCRIPT_EXPLORER }; |
| } |
| if (key == IShowInTarget.class) { |
| return (T) getShowInTarget(); |
| } |
| |
| return null; |
| } |
| |
| @Override |
| public Control getControl() { |
| if (fOutlineViewer != null) { |
| return fOutlineViewer.getControl(); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the <code>JavaOutlineViewer</code> of this view. |
| * |
| * @return the {@link ScriptOutlineViewer} |
| * @since 3.3 |
| */ |
| protected final ScriptOutlineViewer getOutlineViewer() { |
| return fOutlineViewer; |
| } |
| |
| /* |
| * @see ISelectionProvider#getSelection() |
| */ |
| @Override |
| public ISelection getSelection() { |
| if (fOutlineViewer == null) { |
| return StructuredSelection.EMPTY; |
| } |
| return fOutlineViewer.getSelection(); |
| } |
| |
| /** |
| * Returns the <code>IShowInSource</code> for this view. |
| * |
| * @return the {@link IShowInSource} |
| */ |
| protected IShowInSource getShowInSource() { |
| return () -> new ShowInContext(null, |
| getSite().getSelectionProvider().getSelection()); |
| } |
| |
| /** |
| * Returns the <code>IShowInTarget</code> for this view. |
| * |
| * @return the {@link IShowInTarget} |
| */ |
| protected IShowInTarget getShowInTarget() { |
| return context -> { |
| ISelection sel = context.getSelection(); |
| if (sel instanceof ITextSelection) { |
| ITextSelection tsel = (ITextSelection) sel; |
| int offset = tsel.getOffset(); |
| IModelElement element = fEditor.getElementAt(offset); |
| if (element != null) { |
| setSelection(new StructuredSelection(element)); |
| return true; |
| } |
| } else if (sel instanceof IStructuredSelection) { |
| setSelection(sel); |
| return true; |
| } |
| return false; |
| }; |
| } |
| |
| /* |
| * (non-Javadoc) Method declared on Page |
| */ |
| @Override |
| public void init(IPageSite pageSite) { |
| super.init(pageSite); |
| } |
| |
| private void initDragAndDrop() { |
| fDropSupport = new DLTKViewerDropSupport(fOutlineViewer); |
| fDropSupport.start(); |
| |
| new DLTKViewerDragSupport(fOutlineViewer).start(); |
| } |
| |
| /** |
| * Answers if a given model element should be collapsed initially in the |
| * Outline view. |
| * |
| * @param element |
| * the model element |
| * @return <code>true</code> iff the given element should be initially |
| * collapsed |
| */ |
| protected boolean collapseInitially(@NonNull IModelElement element) { |
| final int elementType = element.getElementType(); |
| if (elementType == IModelElement.IMPORT_CONTAINER) { |
| return true; |
| } else if (elementType == IModelElement.TYPE) { |
| // collapse if inner type |
| final IModelElement parent = element.getParent(); |
| return parent != null |
| && parent.getElementType() != IModelElement.SOURCE_MODULE; |
| } else if (elementType == IModelElement.METHOD |
| || elementType == IModelElement.FIELD) { |
| final IModelElement parent = element.getParent(); |
| if (parent != null |
| && parent.getElementType() == IModelElement.TYPE) { |
| // collapse methods/fields of a type if no nested types |
| try { |
| if (!containsTypes((IMember) element)) { |
| return true; |
| } |
| } catch (ModelException e) { |
| DLTKUIPlugin.log(e); |
| } |
| } |
| } |
| return false; |
| } |
| |
| private boolean containsTypes(IMember element) throws ModelException { |
| for (IModelElement child : ((IParent) element).getChildren()) { |
| if (child.getElementType() == IModelElement.TYPE |
| || child instanceof IMember |
| && containsTypes((IMember) child)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| protected void registerSpecialToolbarActions(IActionBars actionBars) { |
| // derived classes could implement it |
| } |
| |
| private void registerToolbarActions(IActionBars actionBars) { |
| IToolBarManager toolBarManager = actionBars.getToolBarManager(); |
| toolBarManager.add(new LexicalSortingAction()); |
| |
| fMemberFilterActionGroup = new MemberFilterActionGroup(fOutlineViewer, |
| fStore); |
| fMemberFilterActionGroup.contributeToToolBar(toolBarManager); |
| |
| fCustomFiltersActionGroup.fillActionBars(actionBars); |
| |
| registerSpecialToolbarActions(actionBars); |
| |
| IMenuManager viewMenuManager = actionBars.getMenuManager(); |
| viewMenuManager.add(new Separator("EndFilterGroup")); //$NON-NLS-1$ |
| |
| fToggleLinkingAction = new ToggleLinkingAction(this); |
| // viewMenuManager.add(new ClassOnlyAction()); |
| viewMenuManager.add(fToggleLinkingAction); |
| |
| // fCategoryFilterActionGroup = new CategoryFilterActionGroup( |
| // fOutlineViewer, |
| // "org.eclipse.jdt.ui.JavaOutlinePage", new IModelElement[] { fInput |
| // }); //$NON-NLS-1$ |
| // fCategoryFilterActionGroup.contributeToViewMenu(viewMenuManager); |
| } |
| |
| /* |
| * @seeorg.eclipse.jface.text.IPostSelectionProvider# |
| * removePostSelectionChangedListener |
| * (org.eclipse.jface.viewers.ISelectionChangedListener) |
| */ |
| @Override |
| public void removePostSelectionChangedListener( |
| ISelectionChangedListener listener) { |
| if (fOutlineViewer != null) { |
| fOutlineViewer.removePostSelectionChangedListener(listener); |
| } else { |
| fPostSelectionChangedListeners.remove(listener); |
| } |
| } |
| |
| /* |
| * @see ISelectionProvider#removeSelectionChangedListener( |
| * ISelectionChangedListener ) |
| */ |
| @Override |
| public void removeSelectionChangedListener( |
| ISelectionChangedListener listener) { |
| if (fOutlineViewer != null) { |
| fOutlineViewer.removeSelectionChangedListener(listener); |
| } else { |
| fSelectionChangedListeners.remove(listener); |
| } |
| } |
| |
| public void select(ISourceReference reference) { |
| if (fOutlineViewer != null) { |
| |
| ISelection s = fOutlineViewer.getSelection(); |
| if (s instanceof IStructuredSelection) { |
| IStructuredSelection ss = (IStructuredSelection) s; |
| List<?> elements = ss.toList(); |
| if (!elements.contains(reference)) { |
| s = (reference == null ? StructuredSelection.EMPTY |
| : new StructuredSelection(reference)); |
| fOutlineViewer.setSelection(s, true); |
| } |
| } |
| } |
| } |
| |
| public void setAction(String actionID, IAction action) { |
| Assert.isNotNull(actionID); |
| if (action == null) { |
| fActions.remove(actionID); |
| } else { |
| fActions.put(actionID, action); |
| } |
| } |
| |
| /* |
| * @see Page#setFocus() |
| */ |
| @Override |
| public void setFocus() { |
| if (fOutlineViewer != null) { |
| fOutlineViewer.getControl().setFocus(); |
| } |
| } |
| |
| public void setInput(IModelElement inputElement) { |
| fInput = inputElement; |
| if (fOutlineViewer != null) { |
| fOutlineViewer.setInput(fInput); |
| updateSelectionProvider(getSite()); |
| } |
| // if (fCategoryFilterActionGroup != null) |
| // fCategoryFilterActionGroup.setInput(new IModelElement[] { fInput }); |
| } |
| |
| /* |
| * @see ISelectionProvider#setSelection(ISelection) |
| */ |
| @Override |
| public void setSelection(ISelection selection) { |
| if (fOutlineViewer != null) { |
| fOutlineViewer.setSelection(selection); |
| } |
| } |
| |
| /* |
| * @since 3.2 |
| */ |
| private void updateSelectionProvider(IPageSite site) { |
| ISelectionProvider provider = fOutlineViewer; |
| if (fInput != null) { |
| ISourceModule cu = (ISourceModule) fInput |
| .getAncestor(IModelElement.SOURCE_MODULE); |
| if (cu != null && !ScriptModelUtil.isPrimary(cu)) { |
| provider = new EmptySelectionProvider(); |
| } |
| } |
| site.setSelectionProvider(provider); |
| } |
| } |