/*
* ShowOutlineAction.java
*
* Copyright (c) 2007
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dcarew.outlinemenu;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IParent;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
import org.eclipse.jdt.ui.IWorkingCopyManager;
import org.eclipse.jdt.ui.JavaElementLabelProvider;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.viewers.DecoratingLabelProvider;
import org.eclipse.jface.viewers.ILabelDecorator;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowPulldownDelegate;
// TODO: show the tree structure better - don't just use spaces
// TODO: use submenus for inner classes?
// TODO: show compilation errors -
// TODO: in the (far) future, have this pulldown menu work for everything that contributes to the outline view
/**
* Adds a class / method pulldown menu to the workspace toolbar.
*
* @author Devon Carew
*/
public class ShowOutlineAction
extends Action
implements IWorkbenchWindowPulldownDelegate
{
private IWorkbenchWindow workbenchWindow;
private ILabelProvider labelProvider;
private Menu oldMenu;
public ShowOutlineAction()
{
}
public Menu getMenu(Control parent)
{
if (oldMenu != null)
oldMenu.dispose();
oldMenu = createMenu(parent);
return oldMenu;
}
public void init(IWorkbenchWindow window)
{
this.workbenchWindow = window;
JavaElementLabelProvider javaLabelProvider = new JavaElementLabelProvider(
JavaElementLabelProvider.SHOW_PARAMETERS | JavaElementLabelProvider.SHOW_OVERLAY_ICONS);
ILabelDecorator javaLabelDecorator = workbenchWindow.getWorkbench().getDecoratorManager().getLabelDecorator();
labelProvider = new DecoratingLabelProvider(javaLabelProvider, javaLabelDecorator);
}
public void dispose()
{
if (oldMenu != null)
oldMenu.dispose();
labelProvider.dispose();
}
public void run(IAction action)
{
// Do we really want to select an element on a button press? the button is right next to the
// pulldown arrow, and the user could hit it by accident. This would make them loose their
// current place in the file.
// // On a button press, select the main type in the file.
// CompilationUnitEditor javaEditor = getCompilationUnitEditor();
//
// if (javaEditor == null)
// return;
//
// ICompilationUnit compilationUnit = getCompilationUnit(javaEditor);
//
// javaEditor.setSelection(compilationUnit.findPrimaryType());
}
public void selectionChanged(IAction action, ISelection selection)
{
}
private CompilationUnitEditor getCompilationUnitEditor()
{
IEditorPart editorPart = null;
if (workbenchWindow != null && workbenchWindow.getActivePage() != null)
editorPart = workbenchWindow.getActivePage().getActiveEditor();
if (editorPart instanceof CompilationUnitEditor)
return (CompilationUnitEditor)editorPart;
return null;
}
private Menu createMenu(Control parent)
{
CompilationUnitEditor javaEditor = getCompilationUnitEditor();
if (javaEditor == null)
return null;
ICompilationUnit compilationUnit = getCompilationUnit(javaEditor);
Menu menu = new Menu(parent);
ISelection selection = javaEditor.getSelectionProvider().getSelection();
try
{
traverse(menu, compilationUnit, selection);
}
catch (JavaModelException exception)
{
OutlinePlugin.log(exception);
}
return menu;
}
private ICompilationUnit getCompilationUnit(CompilationUnitEditor javaEditor)
{
IWorkingCopyManager manager = JavaPlugin.getDefault().getWorkingCopyManager();
return manager.getWorkingCopy(javaEditor.getEditorInput());
}
private void selectElement(IJavaElement element)
{
CompilationUnitEditor javaEditor = getCompilationUnitEditor();
if (javaEditor != null)
javaEditor.setSelection(element);
}
private MenuItem selectedMenuItem;
private void traverse(Menu menu, ICompilationUnit compilationUnit, ISelection selection)
throws JavaModelException
{
selectedMenuItem = null;
IJavaElement[] children = compilationUnit.getChildren();
for (int i = 0; i < children.length; i++)
{
traverse(menu, children[i], "", 0, selection);
}
}
private void traverse(Menu menu, IJavaElement element, String offset, int offsetCount, ISelection selection)
throws JavaModelException
{
if (element instanceof IType || element instanceof IMethod)
{
MenuItem menuItem = new MenuItem(menu, SWT.CHECK);
//menuItem.setText(offset + labelProvider.getText(element));
menuItem.setText(labelProvider.getText(element));
menuItem.setImage(labelProvider.getImage(element));
menuItem.setData(element);
// If the selection is completely contained in a method, then select that method.
// If we run across another method for which the same is true, select that method
// and de-select the old one.
if (element instanceof ISourceReference)
{
if (selectionContainedInElement((ISourceReference)element, selection))
{
if (selectedMenuItem != null)
selectedMenuItem.setSelection(false);
menuItem.setSelection(true);
selectedMenuItem = menuItem;
}
}
menuItem.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent event) {
}
public void widgetSelected(SelectionEvent event) {
selectElement((IJavaElement)event.widget.getData());
}
});
if (element instanceof IParent)
{
IJavaElement[] children = ((IParent)element).getChildren();
for (int i = 0; i < children.length; i++)
{
traverse(menu, children[i], offset + " ", offsetCount + 1, selection);
}
}
}
}
private boolean selectionContainedInElement(ISourceReference element, ISelection isel)
{
if (isel instanceof TextSelection)
{
try
{
TextSelection selection = (TextSelection)isel;
ISourceRange sourceRange = element.getSourceRange();
if (sourceRange == null)
return false;
if ((sourceRange.getOffset() <= selection.getOffset()) &&
(sourceRange.getOffset() + sourceRange.getLength() >= selection.getOffset() + selection.getLength()))
{
return true;
}
}
catch (JavaModelException e)
{
return false;
}
}
return false;
}
}