/******************************************************************************* * 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<>(); 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<ISelectionChangedListener> fSelectionChangedListeners = new ListenerList<>( ListenerList.IDENTITY); private ListenerList<ISelectionChangedListener> fPostSelectionChangedListeners = new ListenerList<>( ListenerList.IDENTITY); private Hashtable<String, IAction> fActions = new Hashtable<>(); 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); } } } } @Override public void addPostSelectionChangedListener( ISelectionChangedListener listener) { if (fOutlineViewer != null) { fOutlineViewer.addPostSelectionChangedListener(listener); } else { fPostSelectionChangedListeners.add(listener); } } @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)); for (ISelectionChangedListener listener : fSelectionChangedListeners) { fSelectionChangedListeners.remove(listener); fOutlineViewer.addSelectionChangedListener(listener); } for (ISelectionChangedListener listener : fPostSelectionChangedListeners) { fPostSelectionChangedListeners.remove(listener); fOutlineViewer.addPostSelectionChangedListener(listener); } 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); } @Override public void removePostSelectionChangedListener( ISelectionChangedListener listener) { if (fOutlineViewer != null) { fOutlineViewer.removePostSelectionChangedListener(listener); } else { fPostSelectionChangedListeners.remove(listener); } } @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); } }