/******************************************************************************* * Copyright (c) 2004, 2014 Tasktop Technologies 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: * Tasktop Technologies - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.internal.java.tasks; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; 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.debug.ui.IDebugModelPresentation; import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin; import org.eclipse.jdt.internal.debug.ui.actions.OpenTypeAction; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.hyperlink.IHyperlink; import org.eclipse.mylyn.tasks.ui.IHighlightingHyperlink; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.progress.UIJob; import org.eclipse.ui.statushandlers.StatusManager; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.ITextEditor; /** * @author Rob Elves */ public class JavaStackTraceFileHyperlink implements IHyperlink, IHighlightingHyperlink { private static final String ID_PLUGIN = "org.eclipse.mylyn.java.tasks"; //$NON-NLS-1$ protected static boolean reflectionErrorLogged; private final IRegion region; private final String traceLine; private final IRegion highlightingRegion; public JavaStackTraceFileHyperlink(IRegion region, String traceLine, IRegion highlightingRegion) { this.region = region; this.traceLine = traceLine; this.highlightingRegion = highlightingRegion; } public IRegion getHyperlinkRegion() { return region; } public String getHyperlinkText() { // ignore return null; } public String getTypeLabel() { // ignore return null; } public void open() { try { String typeName = getTypeName(); int lineNumber = getLineNumber(); // documents start at 0 if (lineNumber > 0) { lineNumber--; } startSourceSearch(typeName, lineNumber); } catch (CoreException e1) { MessageDialog.openInformation(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), Messages.JavaStackTraceFileHyperlink_Open_Type, Messages.JavaStackTraceFileHyperlink_Failed_to_open_type); return; } } /** * Starts a search for the type with the given name. Reports back to 'searchCompleted(...)'. * * @param typeName * the type to search for */ protected void startSourceSearch(final String typeName, final int lineNumber) { Job search = new Job(Messages.JavaStackTraceFileHyperlink_Searching_) { @Override protected IStatus run(IProgressMonitor monitor) { try { // search for the type in the workspace Object result; try { // TODO e3.8 remove reflection try { // e3.7 and earlier: OpenTypeAction.findTypeInWorkspace(typeName); Method findTypeInWorspace = OpenTypeAction.class.getDeclaredMethod("findTypeInWorkspace", //$NON-NLS-1$ String.class); result = findTypeInWorspace.invoke(null, typeName); } catch (NoSuchMethodException e) { // e3.8: OpenTypeAction.findTypeInWorkspace(typeName, false); Method findTypeInWorspace = OpenTypeAction.class.getDeclaredMethod("findTypeInWorkspace", //$NON-NLS-1$ String.class, boolean.class); result = findTypeInWorspace.invoke(null, typeName, false); } } catch (InvocationTargetException e) { if (e.getCause() instanceof CoreException) { searchCompleted(null, typeName, lineNumber, ((CoreException) e.getCause()).getStatus()); } throw e; } searchCompleted(result, typeName, lineNumber, null); } catch (Exception e) { if (!reflectionErrorLogged) { reflectionErrorLogged = true; StatusManager.getManager().handle( new Status(IStatus.ERROR, ID_PLUGIN, "Unexpected error searching for Java type", e), //$NON-NLS-1$ StatusManager.LOG); } } return Status.OK_STATUS; } }; search.schedule(); } protected void searchCompleted(final Object source, final String typeName, final int lineNumber, final IStatus status) { UIJob job = new UIJob(Messages.JavaStackTraceFileHyperlink_link_search_complete) { @Override public IStatus runInUIThread(IProgressMonitor monitor) { if (source == null) { // did not find source MessageDialog.openInformation(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), Messages.JavaStackTraceFileHyperlink_Open_Type, Messages.JavaStackTraceFileHyperlink_Type_could_not_be_located); } else { processSearchResult(source, typeName, lineNumber); } return Status.OK_STATUS; } }; job.setSystem(true); job.schedule(); } /** * The search succeeded with the given result * * @param source * resolved source object for the search * @param typeName * type name searched for * @param lineNumber * line number on link */ protected void processSearchResult(Object source, String typeName, int lineNumber) { IDebugModelPresentation presentation = JDIDebugUIPlugin.getDefault().getModelPresentation(); IEditorInput editorInput = presentation.getEditorInput(source); if (editorInput != null) { String editorId = presentation.getEditorId(editorInput, source); if (editorId != null) { try { IEditorPart editorPart = PlatformUI.getWorkbench() .getActiveWorkbenchWindow() .getActivePage() .openEditor(editorInput, editorId); if (editorPart instanceof ITextEditor && lineNumber >= 0) { ITextEditor textEditor = (ITextEditor) editorPart; IDocumentProvider provider = textEditor.getDocumentProvider(); provider.connect(editorInput); IDocument document = provider.getDocument(editorInput); try { IRegion line = document.getLineInformation(lineNumber); textEditor.selectAndReveal(line.getOffset(), line.getLength()); } catch (BadLocationException e) { MessageDialog.openInformation(PlatformUI.getWorkbench() .getActiveWorkbenchWindow() .getShell(), Messages.JavaStackTraceFileHyperlink_Open_Type, Messages.JavaStackTraceFileHyperlink_Line_not_found_in_type); } provider.disconnect(editorInput); } } catch (CoreException e) { MessageDialog.openInformation(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), Messages.JavaStackTraceFileHyperlink_Open_Type, Messages.JavaStackTraceFileHyperlink_Failed_to_open_type); } } } } // adapted from JavaStackTraceHyperlink private String getTypeName() { int start = traceLine.indexOf('('); int end = traceLine.indexOf(':'); if (start >= 0 && end > start) { // get File name (w/o .java) String typeName = traceLine.substring(start + 1, end); typeName = typeName.substring(0, typeName.indexOf(".")); //$NON-NLS-1$ String qualifier = traceLine.substring(0, start); // remove the method name start = qualifier.lastIndexOf('.'); if (start >= 0) { // remove the class name start = (qualifier.subSequence(0, start).toString()).lastIndexOf('.'); if (start == -1) { start = 0; // default package } } if (start >= 0) { qualifier = qualifier.substring(0, start); } if (qualifier.length() > 0) { typeName = qualifier + "." + typeName; //$NON-NLS-1$ } return typeName.trim(); } return "error"; // TODO: Complain //$NON-NLS-1$ } // adapted from JavaStackTraceHyperlink private int getLineNumber() throws CoreException { int index = traceLine.lastIndexOf(':'); if (index >= 0) { String numText = traceLine.substring(index + 1); index = numText.indexOf(')'); if (index >= 0) { numText = numText.substring(0, index); } try { return Integer.parseInt(numText); } catch (NumberFormatException e) { throw new CoreException(null); } } throw new CoreException(null); } public IRegion getHighlightingRegion() { return (highlightingRegion != null) ? highlightingRegion : region; } }