diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestCaseElement.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestCaseElement.java index 54b8a91..c3967ee 100644 --- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestCaseElement.java +++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestCaseElement.java @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Xavier Coulon - [JUnit] Add "Link with Editor" to JUnit view - https://bugs.eclipse.org/bugs/show_bug.cgi?id=372588 *******************************************************************************/ package org.eclipse.jdt.internal.junit.model; @@ -14,10 +15,26 @@ import org.eclipse.jdt.junit.model.ITestCaseElement; import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaModelException; -public class TestCaseElement extends TestElement implements ITestCaseElement { +import org.eclipse.jdt.internal.junit.JUnitCorePlugin; +/** + * + * @since 3.7 implements {@link IAdaptable} + */ +public class TestCaseElement extends TestElement implements ITestCaseElement, IAdaptable { + + private IType fJavaType = null; + + private IMethod fJavaMethod = null; + private boolean fIgnored; public TestCaseElement(TestSuiteElement parent, String id, String testName) { @@ -41,6 +58,48 @@ return testName.substring(0, index); return testName; } + + /** + * {@inheritDoc} + * @see org.eclipse.jdt.junit.model.ITestCaseElement#getJavaMethod() + */ + public IMethod getJavaMethod() { + if(fJavaMethod == null) { + try { + String testMethodName= getTestMethodName(); + // parameterized tests show an index that should be removed from the name + final int index= testMethodName.indexOf('['); + if (index != -1) { + fJavaMethod= findJavaMethod(testMethodName.substring(0, index)); + } else { + fJavaMethod= findJavaMethod(testMethodName); + } + } catch (JavaModelException e) { + JUnitCorePlugin.log(e); + } + } + return fJavaMethod; + } + + /** + * Finds and returns the {@link IMethod} associated with this {@link TestCaseElement}. + * + * @param methodName the name of the method to find + * @return the corresponding Java method element or null if not found. + * @throws JavaModelException if the inspection of one of the java elements in the given editor failed. + */ + private IMethod findJavaMethod(final String methodName) throws JavaModelException { + final IType type= getJavaType(); + if(type != null) { + final IMethod[] methods= type.getMethods(); + for (int i = 0; i < methods.length; i++) { + if (methods[i].getElementName().equals(methodName)) { + return methods[i]; + } + } + } + return null; + } /** * {@inheritDoc} @@ -48,6 +107,39 @@ */ public String getTestClassName() { return getClassName(); + } + + /** + * @return the Java {@link IType} associated with this {@link TestCaseElement}. + * {@inheritDoc} + * @see org.eclipse.jdt.junit.model.ITestCaseElement#getJavaType() + */ + public IType getJavaType() { + if(fJavaType == null) { + try { + String[] items= getTestClassName().split("\\."); //$NON-NLS-1$ + StringBuilder builder= new StringBuilder(); + boolean primaryTypeFound= false; + for (int i= 0; i < items.length; i++) { + builder.append(items[i]); + boolean firstChar= Character.isUpperCase(items[i].charAt(0)); + if (firstChar && !primaryTypeFound) { + primaryTypeFound= true; + } + if (i < items.length - 1) { + if (primaryTypeFound) { + builder.append('$'); + } else { + builder.append('.'); + } + } + } + fJavaType= getTestRunSession().getLaunchedProject().findType(builder.toString()); + } catch (JavaModelException e) { + JUnitCorePlugin.log(e); + } + } + return fJavaType; } /* @@ -72,4 +164,37 @@ public String toString() { return "TestCase: " + getTestClassName() + "." + getTestMethodName() + " : " + super.toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } + + /** + * Provides support for converting this {@link TestCaseElement} into an {@link IJavaElement}. + * @param adapter the class in which this {@link TestCaseElement} should be adapted. + * @return an object in the request type, or null if it could not be adapted. + * @since 3.7 + */ + public Object getAdapter(Class adapter) { + if(adapter != null && adapter.equals(IJavaElement.class)) { + if(fJavaMethod == null) { + try { + final IJavaProject launchedProject= getTestRunSession().getLaunchedProject(); + final IType type= launchedProject.findType(this.getTestClassName()); + if(type != null && type.exists()) { + final IMethod[] methods= type.getMethods(); + if(methods != null) { + for(int i = 0; i < methods.length; i++) { + if(methods[i].getElementName().equals(this.getJavaMethod())) { + fJavaMethod = methods[i]; + break; + } + } + } + } + + } catch (JavaModelException e) { + JUnitCorePlugin.log(e); + } + } + return fJavaMethod; + } + return null; + } } diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/model/ITestCaseElement.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/model/ITestCaseElement.java index febad01..fefd8e0 100644 --- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/model/ITestCaseElement.java +++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/model/ITestCaseElement.java @@ -7,8 +7,12 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Xavier Coulon - [JUnit] Add "Link with Editor" to JUnit view - https://bugs.eclipse.org/bugs/show_bug.cgi?id=372588 *******************************************************************************/ package org.eclipse.jdt.junit.model; + +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IType; /** * Represents a test case element. @@ -31,10 +35,26 @@ public String getTestMethodName(); /** + * Returns the Java method. + * + * @return returns the Java method. + * @since 3.7 + */ + public IMethod getJavaMethod(); + + /** * Returns the qualified type name of the class the test is contained in. * * @return the qualified type name of the class the test is contained in. */ public String getTestClassName(); + /** + * Returns Java type the test is contained in. + * + * @return Java type the test is contained in. + * @since 3.7 + */ + public IType getJavaType(); + } diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestRunnerViewPart.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestRunnerViewPart.java index ccf104e..55d7870 100644 --- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestRunnerViewPart.java +++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestRunnerViewPart.java @@ -16,6 +16,7 @@ * Andrew Eisenberg - [JUnit] Rerun failed first does not work with JUnit4 - https://bugs.eclipse.org/bugs/show_bug.cgi?id=140392 * Thirumala Reddy Mutchukota - [JUnit] Avoid rerun test launch on UI thread - https://bugs.eclipse.org/bugs/show_bug.cgi?id=411841 * Andrew Eisenberg - [JUnit] Add a monospace font option for the junit results view - https://bugs.eclipse.org/bugs/show_bug.cgi?id=411794 + * Xavier Coulon - [JUnit] Add "Link with Editor" to JUnit view - https://bugs.eclipse.org/bugs/show_bug.cgi?id=372588 *******************************************************************************/ package org.eclipse.jdt.internal.junit.ui; @@ -96,6 +97,7 @@ import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.ISelection; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IEditorActionBarContributor; @@ -149,6 +151,9 @@ import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; +import org.eclipse.jdt.ui.PreferenceConstants; + +import org.eclipse.jdt.internal.ui.actions.AbstractToggleLinkingAction; import org.eclipse.jdt.internal.ui.viewsupport.ViewHistory; /** @@ -210,6 +215,14 @@ private Action fPreviousAction; private StopAction fStopAction; + + + /** + * Helper to open and activate editors. + * @since 3.7 + */ + private LinkWithEditorAction fLinkWithEditorAction; + private JUnitCopyAction fCopyAction; private Action fPasteAction; @@ -705,6 +718,7 @@ startUpdateJobs(); fStopAction.setEnabled(true); + fLinkWithEditorAction.setEnabled(true); fRerunLastTestAction.setEnabled(true); } @@ -722,6 +736,7 @@ if (isDisposed()) return; fStopAction.setEnabled(lastLaunchIsKeptAlive()); + fLinkWithEditorAction.setEnabled(fTestRunSession != null); updateRerunFailedFirstAction(); processChangesInUI(); if (hasErrorsOrFailures()) { @@ -897,6 +912,33 @@ stopTest(); setEnabled(false); } + } + + /** + * This action toggles whether this {@link TestRunnerViewPart} links + * its selection to the active editor. + * + */ + private class LinkWithEditorAction extends AbstractToggleLinkingAction { + + LinkWithEditorAction() { + boolean isLinkingEnabled= PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.LINK_BROWSING_JUNIT_TESTS_TO_EDITOR); + setChecked(isLinkingEnabled); + } + + @Override + public void run() { + PreferenceConstants.getPreferenceStore().setValue(PreferenceConstants.LINK_BROWSING_JUNIT_TESTS_TO_EDITOR, isChecked()); + setLinkingActive(isChecked()); + } + } + + /** + * @return {@code true} if the {@link LinkWithEditorAction} is checked, false otherwise. + * @since 3.7 + */ + public boolean isLinkWithEditorActive() { + return fLinkWithEditorAction.isChecked(); } private class RerunLastAction extends Action { @@ -1200,6 +1242,18 @@ } } + /** + * Activate the 'Link with Editor' in the current {@link IWorkbenchPage}. + * (The {@link TestViewer} will respond to {@link ISelection} changes.) + * + * @param active boolean to indicate if the link with editor is active ({@code true}) or not ({@code false}) + * + * @since 3.7 + */ + public void setLinkingActive(boolean active) { + fTestViewer.setLinkingActive(getSite().getPage(), active); + } + private void startUpdateJobs() { postSyncProcessChanges(); @@ -1507,11 +1561,13 @@ startUpdateJobs(); fStopAction.setEnabled(true); + fLinkWithEditorAction.setEnabled(true); } else /* old or fresh session: don't want jobs at this stage */ { stopUpdateJobs(); fStopAction.setEnabled(fTestRunSession.isKeptAlive()); + fLinkWithEditorAction.setEnabled(fTestRunSession != null); fTestViewer.expandFirstLevel(); } } @@ -1579,6 +1635,7 @@ if (fFailureTrace != null) { fFailureTrace.dispose(); } + //getSite().getPage().removeSelectionListener(fTestViewer); } private void disposeImages() { @@ -1783,6 +1840,7 @@ if (!testRunSessions.isEmpty()) { fTestRunSessionListener.sessionAdded(testRunSessions.get(0)); } + } private void addDropAdapter(Composite parent) { @@ -1887,6 +1945,9 @@ fStopAction= new StopAction(); fStopAction.setEnabled(false); + fLinkWithEditorAction= new LinkWithEditorAction(); + fLinkWithEditorAction.setEnabled(false); + fRerunLastTestAction= new RerunLastAction(); IHandlerService handlerService= (IHandlerService) getSite().getWorkbenchWindow().getService(IHandlerService.class); IHandler handler = new AbstractHandler() { @@ -1937,7 +1998,8 @@ toolBar.add(fRerunFailedFirstAction); toolBar.add(fStopAction); toolBar.add(fViewHistory.createHistoryDropDownAction()); - + toolBar.add(new Separator()); + toolBar.add(fLinkWithEditorAction); viewMenu.add(fShowTestHierarchyAction); viewMenu.add(fShowTimeAction); diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestViewer.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestViewer.java index e050d66..b85afd6 100644 --- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestViewer.java +++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestViewer.java @@ -9,6 +9,7 @@ * IBM Corporation - initial API and implementation * Brock Janiczak (brockj@tpg.com.au) * - https://bugs.eclipse.org/bugs/show_bug.cgi?id=102236: [JUnit] display execution time next to each test + * Xavier Coulon - [JUnit] Add "Link with Editor" to JUnit view - https://bugs.eclipse.org/bugs/show_bug.cgi?id=372588 *******************************************************************************/ package org.eclipse.jdt.internal.junit.ui; @@ -21,7 +22,9 @@ import java.util.List; import java.util.ListIterator; +import org.eclipse.jdt.junit.model.ITestCaseElement; import org.eclipse.jdt.junit.model.ITestElement; +import org.eclipse.jdt.junit.model.ITestSuiteElement; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.Clipboard; @@ -38,7 +41,10 @@ import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.viewers.AbstractTreeViewer; +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.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; @@ -48,12 +54,25 @@ import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; +import org.eclipse.jface.text.ITextSelection; + +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IPartListener2; +import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchPartReference; +import org.eclipse.ui.PartInitException; import org.eclipse.ui.part.PageBook; import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; @@ -64,6 +83,11 @@ import org.eclipse.jdt.internal.junit.model.TestRunSession; import org.eclipse.jdt.internal.junit.model.TestSuiteElement; +import org.eclipse.jdt.ui.JavaUI; + +import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor; +import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility; +import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor; import org.eclipse.jdt.internal.ui.viewsupport.ColoringLabelProvider; import org.eclipse.jdt.internal.ui.viewsupport.SelectionProviderMediator; @@ -302,6 +326,27 @@ testElement= (TestElement) selection.getFirstElement(); } fTestRunnerPart.handleTestSelected(testElement); + // if LinkWithEditor is active, reveal the JavaEditor and select the java method + // matching the selected test element, even if the JavaEditor is opened by not active. + if(fTestRunnerPart.isLinkWithEditorActive() && testElement instanceof TestCaseElement) { + handleTestSelected((TestCaseElement) testElement); + } + } + + /** + * Reacts to a selection change in another {@link IWorkbenchPart}. If the given + * {@link ISelection} matches an existing {@link TestCaseElement} in the viewer, this later will + * be selected. + * + * @param part the part in which the selection changed. + * @param selection the new selection + * + * @since 3.7 + */ + public void selectionChanged(IWorkbenchPart part, ISelection selection) { + if(fTestRunnerPart.isLinkWithEditorActive() && fTestRunnerPart.isLinkWithEditorActive() && part instanceof CompilationUnitEditor) { + setSelection((CompilationUnitEditor)part); + } } public synchronized void setShowTime(boolean showTime) { @@ -568,6 +613,64 @@ fTreeViewer.reveal(current); } + /** + * Sets the current selection from the given {@link CompilationUnitEditor} and its selection. + * @param editor the selected Java Element in the active Java Editor + * + */ + private void setSelection(final CompilationUnitEditor editor) { + final ISelectionProvider selectionProvider = editor.getSelectionProvider(); + final IJavaElement selectedJavaElement= getSelectedJavaElementInEditor(JavaUI.getEditorInputJavaElement(editor.getEditorInput()), selectionProvider.getSelection()); + if(selectedJavaElement != null) { + setSelection(selectedJavaElement); + fJavaEditorSelectionListener = new JavaEditorSelectionListener((ICompilationUnit)selectedJavaElement.getAncestor(IJavaElement.COMPILATION_UNIT)); + ((IPostSelectionProvider)editor.getSelectionProvider()).addPostSelectionChangedListener(fJavaEditorSelectionListener); + } + } + + /** + * Selects the the current selection from the given {@link IJavaElement} if it is an {@link IMethod} + * @param activeJavaElement the selected Java Element in the active Java Editor + * + */ + private void setSelection(final IJavaElement activeJavaElement) { + // select the method in the JUnit ViewPart + // skip if history was cleared and 'Link with Editor' is still enabled. + if(fTestRunSession != null && activeJavaElement != null && activeJavaElement.getElementType() == IJavaElement.METHOD) { + final IMethod activeJavaMethod = (IMethod)activeJavaElement; + final IType activeJavaType = (IType)activeJavaMethod.getAncestor(IJavaElement.TYPE); + final String testClassName= activeJavaType.getFullyQualifiedName(); + final String testMethodName= activeJavaMethod.getElementName(); + final ITestCaseElement activeTestCaseElement = findTestCaseElement(fTestRunSession.getTestRoot(), testClassName, testMethodName); + if(activeTestCaseElement != null) { + final StructuredSelection selection= new StructuredSelection(activeTestCaseElement); + if(!selection.equals(getActiveViewer().getSelection())) { + fSelectionProvider.setSelection(selection, true); + } + } + + } + } + + private ITestCaseElement findTestCaseElement(final ITestSuiteElement parentElement, final String testClassName, final String testMethodName) { + for(ITestElement childElement : parentElement.getChildren()) { + if(childElement instanceof ITestCaseElement) { + ITestCaseElement testCaseElement = (ITestCaseElement)childElement; + if (testCaseElement.getJavaType() != null && testCaseElement.getJavaType().getFullyQualifiedName().equals(testClassName) && testCaseElement.getJavaMethod() != null + && testCaseElement.getJavaMethod().getElementName().equals(testMethodName)) { + return testCaseElement; + } + } else if(childElement instanceof ITestSuiteElement) { + final ITestCaseElement localResult= findTestCaseElement((ITestSuiteElement)childElement, testClassName, testMethodName); + if(localResult != null) { + return localResult; + } + } + } + return null; + + } + public void selectFirstFailure() { TestCaseElement firstFailure= getNextChildFailure(fTestRunSession.getTestRoot(), true); if (firstFailure != null) @@ -680,6 +783,187 @@ public void expandFirstLevel() { fTreeViewer.expandToLevel(2); } + + /** + * Links the selected test method with the Java Editor + * @param page the currently active page + * @param active boolean to indicate if the link with editor is enabled ({@code true}) or not ({@code false}) + * + * @since 3.7 + */ + public void setLinkingActive(final IWorkbenchPage page, final boolean active) { + if(page == null) { + return; + } + if (active) { + // add an IPartListener for future editor activations/opening/closing/etc. + page.addPartListener(fLinkWithEditorPartListener); + page.addPostSelectionListener(fLinkWithEditorSelectionListener); + if(page.getActiveEditor() instanceof CompilationUnitEditor) { + setSelection((CompilationUnitEditor)page.getActiveEditor()); + } + } else { + // removes the IPartListener + page.removePartListener(fLinkWithEditorPartListener); + page.removePostSelectionListener(fLinkWithEditorSelectionListener); + } + } + + private final IPartListener2 fLinkWithEditorPartListener= new IPartListener2() { + public void partVisible(IWorkbenchPartReference partRef) {} + public void partBroughtToTop(IWorkbenchPartReference partRef) {} + public void partHidden(IWorkbenchPartReference partRef) {} + public void partOpened(IWorkbenchPartReference partRef) {} + public void partInputChanged(IWorkbenchPartReference partRef) {} + public void partClosed(IWorkbenchPartReference partRef) {} + public void partActivated(IWorkbenchPartReference partRef) { + if (partRef instanceof IEditorReference) { + editorActivated(((IEditorReference) partRef).getEditor(true)); + } + } + + public void partDeactivated(IWorkbenchPartReference partRef) { + if (partRef instanceof IEditorReference) { + editorDeactivated(((IEditorReference) partRef).getEditor(true)); + } + } + + }; + + private ISelectionListener fLinkWithEditorSelectionListener = new ISelectionListener() { + + public void selectionChanged(IWorkbenchPart editor, ISelection selection) { + if(editor instanceof CompilationUnitEditor && selection instanceof ITextSelection) { + setSelection((CompilationUnitEditor)editor); + } + } + + }; + + private JavaEditorSelectionListener fJavaEditorSelectionListener; + + /** + * Static Inner Java Editor selection listener + * When the user moves to another + * @since 3.7 + */ + private class JavaEditorSelectionListener implements ISelectionChangedListener { + + private final ICompilationUnit compilationUnit; + + JavaEditorSelectionListener(final ICompilationUnit compilationUnit) { + this.compilationUnit = compilationUnit; + } + + public void selectionChanged(final SelectionChangedEvent event) { + IJavaElement selectedJavaElement= getSelectedJavaElementInEditor(compilationUnit, event.getSelection()); + setSelection(selectedJavaElement); + } + + /** + * Overriding java.lang.Object#hashCode() using the + * {@link ICompilationUnit#getHandleIdentifier()} value to avoid duplicate listener + * registrations in the {@link JavaEditor}'s {@link IPostSelectionProvider}. + */ + @Override + public int hashCode() { + final int prime= 31; + int result= 1; + result= prime * result + ((compilationUnit == null) ? 0 : compilationUnit.getHandleIdentifier().hashCode()); + return result; + } + + /** + * Overriding java.lang.Object#equals() using the + * {@link ICompilationUnit#getHandleIdentifier()} value to avoid duplicate listener + * registrations in the {@link JavaEditor}'s {@link IPostSelectionProvider}. + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + JavaEditorSelectionListener other= (JavaEditorSelectionListener)obj; + if (compilationUnit == null) { + if (other.compilationUnit != null) { + return false; + } + } else if (!compilationUnit.getHandleIdentifier().equals(other.compilationUnit.getHandleIdentifier())) { + return false; + } + return true; + } + } + + /** + * An editor has been activated. Set the selection in this JUnit ViewPart + * to match the editor's input, if linking is enabled. + * @param editor the activated editor + */ + private void editorActivated(IEditorPart editor) { + if(!(editor instanceof CompilationUnitEditor)) { + return; + } + CompilationUnitEditor javaEditor= (CompilationUnitEditor)editor; + setSelection(javaEditor); + } + + private IJavaElement getSelectedJavaElementInEditor(final IJavaElement javaElement, final ISelection selection) { + if(javaElement instanceof ICompilationUnit && selection instanceof ITextSelection) { + try { + return ((ICompilationUnit)javaElement).getElementAt(((ITextSelection)selection).getOffset()); + } catch(JavaModelException e) { + JUnitPlugin.log(e); + } + } + return null; + } + + /** + * An editor has been deactivated. + * @param editor the activated editor + */ + private void editorDeactivated(IEditorPart editor) { + if(fJavaEditorSelectionListener != null & editor instanceof CompilationUnitEditor) { + final IPostSelectionProvider selectionProvider = (IPostSelectionProvider)((CompilationUnitEditor)editor).getSelectionProvider(); + selectionProvider.removePostSelectionChangedListener(fJavaEditorSelectionListener); + } + } + + private void handleTestSelected(final TestCaseElement testCaseElement) { + try { + final IType type= testCaseElement.getJavaType(); + final IEditorPart editor= EditorUtility.isOpenInEditor(type); + final IMethod selectedMethod= testCaseElement.getJavaMethod(); + if(selectedMethod != null && editor != null && editor instanceof JavaEditor) { + final JavaEditor javaEditor = (JavaEditor)editor; + final ITextSelection javaEditorSelection= (ITextSelection)javaEditor.getSelectionProvider().getSelection(); + final IJavaElement javaEditorSelectedElement= type.getCompilationUnit().getElementAt(javaEditorSelection.getOffset()); + IEditorPart selectedMethodEditor = EditorUtility.isOpenInEditor(selectedMethod); + // checks if the editor is already open or not + if(selectedMethodEditor != null) { + EditorUtility.openInEditor(selectedMethod, false); + if(!selectedMethod.equals(javaEditorSelectedElement)) { + EditorUtility.revealInEditor(selectedMethodEditor, selectedMethod); + } + } + if(!selectedMethod.equals(javaEditorSelectedElement)) { + JavaUI.revealInEditor(editor, (IJavaElement)selectedMethod); + } + } + } catch(JavaModelException e) { + JUnitPlugin.log(e); + } catch(PartInitException e) { + // ignore if no editor input can be found + } + } + } diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/PreferenceConstants.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/PreferenceConstants.java index 9709fe8..69bcd75 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/PreferenceConstants.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/PreferenceConstants.java @@ -460,6 +460,16 @@ */ public static final String LINK_BROWSING_PACKAGES_TO_EDITOR= "org.eclipse.jdt.ui.browsing.packagestoeditor"; //$NON-NLS-1$ + /** + * A named preference that controls whether the JUnit view's selection is + * linked to the active editor. + *

+ * Value is of type Boolean. + *

+ * @since 3.9 + */ + public static final String LINK_BROWSING_JUNIT_TESTS_TO_EDITOR= "org.eclipse.jdt.ui.browsing.junitteststoeditor"; //$NON-NLS-1$ + /**