/******************************************************************************* * Copyright (c) 2007 IBM Corporation. * 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: * Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation *******************************************************************************/ package org.eclipse.imp.editor; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.imp.editor.OutlineLabelProvider.IElementImageProvider; import org.eclipse.imp.editor.internal.TreeDiffer; import org.eclipse.imp.parser.IModelListener; import org.eclipse.imp.parser.IParseController; import org.eclipse.imp.parser.ISourcePositionLocator; import org.eclipse.imp.runtime.RuntimePlugin; import org.eclipse.imp.services.IEntityNameLocator; import org.eclipse.imp.services.base.TreeModelBuilderBase; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ITreeSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.IPageSite; import org.eclipse.ui.texteditor.ITextEditor; import org.eclipse.ui.views.contentoutline.ContentOutlinePage; public class IMPOutlinePage extends ContentOutlinePage implements IModelListener { private final OutlineContentProviderBase fContentProvider; private final TreeModelBuilderBase fModelBuilder; private final ILabelProvider fLabelProvider; private final IElementImageProvider fImageProvider; private final IParseController fParseController; private final IRegionSelectionService regionSelector; private final IEntityNameLocator fNameLocator; /** * Constructor flavor introduced for backward-compatibility with clients that extend this * class but do not furnish an IEntityNameLocator. */ public IMPOutlinePage(IParseController parseController, TreeModelBuilderBase modelBuilder, ILabelProvider labelProvider, IElementImageProvider imageProvider, IRegionSelectionService regionSelector) { this(parseController, modelBuilder, labelProvider, imageProvider, null, regionSelector); } public IMPOutlinePage(IParseController parseController, TreeModelBuilderBase modelBuilder, ILabelProvider labelProvider, IElementImageProvider imageProvider, IEntityNameLocator nameLocator, IRegionSelectionService regionSelector) { fParseController= parseController; fModelBuilder= modelBuilder; fLabelProvider= labelProvider; fImageProvider= imageProvider; fNameLocator= nameLocator; // SMS 21 Aug 2008 if (regionSelector != null) this.regionSelector = regionSelector; else { this.regionSelector = new IRegionSelectionService() { public void selectAndReveal(int startOffset, int length) { IEditorPart activeEditor= PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor(); ITextEditor textEditor= (ITextEditor) activeEditor; textEditor.selectAndReveal(startOffset, length); } }; } fContentProvider= new OutlineContentProviderBase(null) { private ModelTreeNode fOldTree= null; public Object[] getChildren(Object element) { ModelTreeNode node= (ModelTreeNode) element; return node.getChildren(); } public Object getParent(Object element) { ModelTreeNode node= (ModelTreeNode) element; return node.getParent(); } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { super.inputChanged(viewer, oldInput, newInput); if (fOldTree != null) { TreeDiffer treeDiffer= new TreeDiffer((TreeViewer) viewer, fLabelProvider); treeDiffer.diff((ModelTreeNode) oldInput, (ModelTreeNode) newInput); } fOldTree= (ModelTreeNode) newInput; } }; } public AnalysisRequired getAnalysisRequired() { return IModelListener.AnalysisRequired.SYNTACTIC_ANALYSIS; } public void update(final IParseController parseController, IProgressMonitor monitor) { if (getTreeViewer() != null && !getTreeViewer().getTree().isDisposed()) { getTreeViewer().getTree().getDisplay().asyncExec(new Runnable() { public void run() { if (getTreeViewer() != null && !getTreeViewer().getTree().isDisposed()) getTreeViewer().setInput(fModelBuilder.buildTree(fParseController.getCurrentAst())); } }); } } @Override public void selectionChanged(SelectionChangedEvent event) { super.selectionChanged(event); ITreeSelection sel= (ITreeSelection) event.getSelection(); if (sel.isEmpty()) return; ModelTreeNode selNode= (ModelTreeNode) sel.getFirstElement(); ISourcePositionLocator locator= fParseController.getSourcePositionLocator(); Object node= selNode.getASTNode(); if (fNameLocator != null) { Object name= fNameLocator.getName(node); if (name != null) { node= name; } } int startOffset= locator.getStartOffset(node); int endOffset= locator.getEndOffset(node); int length= endOffset - startOffset + 1; regionSelector.selectAndReveal(startOffset, length); // IEditorPart activeEditor= PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor(); // AbstractTextEditor textEditor= (AbstractTextEditor) activeEditor; // // textEditor.selectAndReveal(startOffset, length); } public void createControl(Composite parent) { super.createControl(parent); TreeViewer viewer= getTreeViewer(); viewer.setContentProvider(fContentProvider); if (fLabelProvider != null) { viewer.setLabelProvider(fLabelProvider); } viewer.addSelectionChangedListener(this); ModelTreeNode rootNode= fModelBuilder.buildTree(fParseController.getCurrentAst()); viewer.setInput(rootNode); viewer.setAutoExpandLevel(2); IPageSite site= getSite(); IActionBars actionBars= site.getActionBars(); registerToolbarActions(actionBars); } class LexicalSortingAction extends Action { // TODO Need to introduce some API to provide language-specific "categories" that get used for sorting and filtering; perhaps on ModelTreeNode? private ViewerComparator fElementComparator= new ViewerComparator() { @Override public int compare(Viewer viewer, Object e1, Object e2) { ModelTreeNode t1= (ModelTreeNode) e1; ModelTreeNode t2= (ModelTreeNode) e2; int cat1= t1.getCategory(); int cat2= t2.getCategory(); if (cat1 == cat2) { return fLabelProvider.getText(t1).compareTo(fLabelProvider.getText(t2)); } return cat1 - cat2; } }; private ISourcePositionLocator fLocator= fParseController.getSourcePositionLocator(); private ViewerComparator fPositionComparator= new ViewerComparator() { @Override public int compare(Viewer viewer, Object e1, Object e2) { int pos1= fLocator.getStartOffset(e1); int pos2= fLocator.getStartOffset(e2); return pos1 - pos2; } }; public LexicalSortingAction() { super(); // PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IJavaHelpContextIds.LEXICAL_SORTING_OUTLINE_ACTION); setText("Sort"); setToolTipText("Sort by name"); setDescription("Sort entries lexically by name"); ImageDescriptor desc= RuntimePlugin.getImageDescriptor("icons/alphab_sort_co.gif"); //$NON-NLS-1$ this.setHoverImageDescriptor(desc); this.setImageDescriptor(desc); boolean checked= RuntimePlugin.getInstance().getPreferenceStore().getBoolean("LexicalSortingAction.isChecked"); //$NON-NLS-1$ valueChanged(checked, false); } public void run() { valueChanged(isChecked(), true); } private void valueChanged(final boolean on, boolean store) { final TreeViewer outlineViewer= getTreeViewer(); setChecked(on); BusyIndicator.showWhile(outlineViewer.getControl().getDisplay(), new Runnable() { public void run() { if (on) outlineViewer.setComparator(fElementComparator); else outlineViewer.setComparator(fPositionComparator); } }); if (store) { // RMF Need to store separate settings per language RuntimePlugin.getInstance().getPreferenceStore().setValue("LexicalSortingAction.isChecked", on); //$NON-NLS-1$ } } } private void registerToolbarActions(IActionBars actionBars) { IToolBarManager toolBarManager= actionBars.getToolBarManager(); toolBarManager.add(new LexicalSortingAction()); // fMemberFilterActionGroup= new MemberFilterActionGroup(fOutlineViewer, "org.eclipse.jdt.ui.JavaOutlinePage"); //$NON-NLS-1$ // fMemberFilterActionGroup.contributeToToolBar(toolBarManager); // // fCustomFiltersActionGroup.fillActionBars(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 IJavaElement[] {fInput}); //$NON-NLS-1$ // fCategoryFilterActionGroup.contributeToViewMenu(viewMenuManager); } }