/*******************************************************************************
* Copyright (c) 2006, 2008 Wind River Systems, Inc. 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:
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.ui.typehierarchy;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.Region;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType;
import org.eclipse.cdt.core.dom.ast.IEnumeration;
import org.eclipse.cdt.core.dom.ast.IEnumerator;
import org.eclipse.cdt.core.dom.ast.IField;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.ITypedef;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexManager;
import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.IFunctionDeclaration;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.internal.ui.util.ExceptionHandler;
import org.eclipse.cdt.internal.ui.util.StatusLineHandler;
import org.eclipse.cdt.internal.ui.viewsupport.IndexUI;
public class TypeHierarchyUI {
public static THViewPart open(ICElement input, IWorkbenchWindow window) {
if (!isValidInput(input)) {
return null;
}
ICElement memberInput= null;
if (!isValidTypeInput(input)) {
memberInput= input;
input= memberInput.getParent();
if (!isValidTypeInput(input)) {
ICElement[] inputs= findInput(memberInput);
if (inputs != null) {
input= inputs[0];
memberInput= inputs[1];
}
}
}
if (isValidTypeInput(input)) {
return openInViewPart(window, input, memberInput);
}
return null;
}
private static THViewPart openInViewPart(IWorkbenchWindow window, ICElement input, ICElement member) {
IWorkbenchPage page= window.getActivePage();
try {
THViewPart result= (THViewPart)page.showView(CUIPlugin.ID_TYPE_HIERARCHY);
result.setInput(input, member);
return result;
} catch (CoreException e) {
ExceptionHandler.handle(e, window.getShell(), Messages.TypeHierarchyUI_OpenTypeHierarchy, null);
}
return null;
}
public static ICElement[] getInput(final ITextEditor editor, IRegion region) {
if (editor != null) {
final IEditorInput editorInput = editor.getEditorInput();
ICElement inputCElement = CUIPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(editorInput);
if (inputCElement != null) {
final ICProject project= inputCElement.getCProject();
try {
return findInput(project, editorInput, region);
} catch (CoreException e) {
CUIPlugin.log(e);
}
}
}
return null;
}
public static void open(final ITextEditor editor, final ITextSelection sel) {
if (editor != null) {
ICElement inputCElement = CUIPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(editor.getEditorInput());
if (inputCElement != null) {
final ICProject project= inputCElement.getCProject();
final IEditorInput editorInput = editor.getEditorInput();
final Display display= Display.getCurrent();
Job job= new Job(Messages.TypeHierarchyUI_OpenTypeHierarchy) {
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
StatusLineHandler.clearStatusLine(editor.getSite());
IRegion reg= new Region(sel.getOffset(), sel.getLength());
final ICElement[] elems= findInput(project, editorInput, reg);
if (elems != null && elems.length == 2) {
display.asyncExec(new Runnable() {
public void run() {
openInViewPart(editor.getSite().getWorkbenchWindow(), elems[0], elems[1]);
}});
} else {
StatusLineHandler.showStatusLineMessage(editor.getSite(),
Messages.TypeHierarchyUI_OpenFailure_message);
}
return Status.OK_STATUS;
}
catch (CoreException e) {
return e.getStatus();
}
}
};
job.setUser(true);
job.schedule();
}
}
}
private static ICElement[] findInput(ICProject project, IEditorInput editorInput, IRegion sel) throws CoreException {
try {
IIndex index= CCorePlugin.getIndexManager().getIndex(project, IIndexManager.ADD_DEPENDENCIES | IIndexManager.ADD_DEPENDENT);
index.acquireReadLock();
try {
IASTName name= IndexUI.getSelectedName(editorInput, sel);
if (name != null) {
IBinding binding= name.resolveBinding();
if (!isValidInput(binding)) {
return null;
}
ICElement member= null;
if (!isValidTypeInput(binding)) {
member= findDeclaration(project, index, name, binding);
name= null;
binding= findTypeBinding(binding);
}
if (isValidTypeInput(binding)) {
ICElement input= findDefinition(project, index, name, binding);
if (input != null) {
return new ICElement[] {input, member};
}
}
}
}
finally {
index.releaseReadLock();
}
}
catch (CoreException e) {
CUIPlugin.log(e);
}
catch (InterruptedException e) {
}
return null;
}
private static ICElement[] findInput(ICElement member) {
ICProject project= member.getCProject();
try {
IIndex index= CCorePlugin.getIndexManager().getIndex(project, IIndexManager.ADD_DEPENDENCIES | IIndexManager.ADD_DEPENDENT);
index.acquireReadLock();
try {
IIndexName name= IndexUI.elementToName(index, member);
if (name != null) {
member= IndexUI.getCElementForName(project, index, name);
IBinding binding= index.findBinding(name);
binding= findTypeBinding(binding);
if (isValidTypeInput(binding)) {
ICElement input= findDefinition(project, index, null, binding);
if (input != null) {
return new ICElement[] {input, member};
}
}
}
}
finally {
index.releaseReadLock();
}
}
catch (CoreException e) {
CUIPlugin.log(e);
}
catch (InterruptedException e) {
}
return null;
}
private static IBinding findTypeBinding(IBinding memberBinding) {
try {
if (memberBinding instanceof IEnumerator) {
IType type= ((IEnumerator) memberBinding).getType();
if (type instanceof IBinding) {
return (IBinding) type;
}
}
else if (memberBinding instanceof ICPPMember) {
return ((ICPPMember) memberBinding).getClassOwner();
}
else if (memberBinding instanceof IField) {
return ((IField) memberBinding).getCompositeTypeOwner();
}
} catch (DOMException e) {
// don't log problem bindings
}
return null;
}
private static ICElement findDefinition(ICProject project, IIndex index, IASTName name, IBinding binding)
throws CoreException {
if (name != null && name.isDefinition()) {
return IndexUI.getCElementForName(project, index, name);
}
ICElement[] elems= IndexUI.findAllDefinitions(index, binding);
if (elems.length > 0) {
return elems[0];
}
return IndexUI.findAnyDeclaration(index, project, binding);
}
private static ICElement findDeclaration(ICProject project, IIndex index, IASTName name, IBinding binding)
throws CoreException {
if (name != null && name.isDefinition()) {
return IndexUI.getCElementForName(project, index, name);
}
ICElement[] elems= IndexUI.findAllDefinitions(index, binding);
if (elems.length > 0) {
return elems[0];
}
return IndexUI.findAnyDeclaration(index, project, binding);
}
public static boolean isValidInput(IBinding binding) {
if (isValidTypeInput(binding)
|| binding instanceof ICPPMember
|| binding instanceof IEnumerator
|| binding instanceof IField) {
return true;
}
return false;
}
public static boolean isValidTypeInput(IBinding binding) {
if (binding instanceof ICompositeType
|| binding instanceof IEnumeration
|| binding instanceof ITypedef) {
return true;
}
return false;
}
public static boolean isValidInput(ICElement elem) {
if (elem == null) {
return false;
}
if (isValidTypeInput(elem)) {
return true;
}
switch (elem.getElementType()) {
case ICElement.C_FIELD:
case ICElement.C_METHOD:
case ICElement.C_METHOD_DECLARATION:
case ICElement.C_TEMPLATE_METHOD:
case ICElement.C_TEMPLATE_METHOD_DECLARATION:
case ICElement.C_ENUMERATOR:
return true;
}
return false;
}
public static boolean isValidTypeInput(ICElement elem) {
if (elem == null) {
return false;
}
switch (elem.getElementType()) {
case ICElement.C_CLASS:
case ICElement.C_STRUCT:
case ICElement.C_UNION:
case ICElement.C_CLASS_DECLARATION:
case ICElement.C_STRUCT_DECLARATION:
case ICElement.C_UNION_DECLARATION:
case ICElement.C_ENUMERATION:
case ICElement.C_TYPEDEF:
// case ICElement.C_TEMPLATE_CLASS:
// case ICElement.C_TEMPLATE_CLASS_DECLARATION:
// case ICElement.C_TEMPLATE_STRUCT:
// case ICElement.C_TEMPLATE_STRUCT_DECLARATION:
// case ICElement.C_TEMPLATE_UNION:
// case ICElement.C_TEMPLATE_UNION_DECLARATION:
return true;
}
return false;
}
static String getLocalElementSignature(ICElement element) {
if (element != null) {
try {
switch (element.getElementType()) {
case ICElement.C_METHOD:
case ICElement.C_METHOD_DECLARATION:
return ((IFunctionDeclaration) element).getSignature();
case ICElement.C_FIELD:
return element.getElementName();
}
} catch (CModelException e) {
CUIPlugin.log(e);
}
}
return null;
}
}