/* * Copyright 2009-2016 the original author or authors. * * 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.codehaus.groovy.eclipse.debug.ui; import java.util.HashMap; import java.util.Map; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.ModuleNode; import org.codehaus.jdt.groovy.model.GroovyCompilationUnit; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; 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.core.DebugPlugin; import org.eclipse.debug.core.model.IBreakpoint; import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.ISourceRange; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.debug.core.IJavaLineBreakpoint; import org.eclipse.jdt.debug.core.JDIDebugModel; import org.eclipse.jdt.internal.debug.ui.BreakpointUtils; import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin; import org.eclipse.jdt.internal.debug.ui.actions.ActionDelegateHelper; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.viewers.ISelection; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.IEditorStatusLine; import org.eclipse.ui.texteditor.ITextEditor; /** * Toggles a line breakpoint in a Java editor. * Based on org.eclipse.jdt.internal.debug.ui.actions.ToggleBreakpointAdapter, * but uses * BreakpointLocationVerifierJob and ValidBreakpointLocationLocator from this * package and does not * support field watchpoints. * * Borrowed from same class in AJDT */ public class ToggleBreakpointAdapter implements IToggleBreakpointsTargetExtension { public final static Object TOGGLE_BREAKPOINT_FAMILY = new Object(); public ToggleBreakpointAdapter() { // init helper in UI thread ActionDelegateHelper.getDefault(); } protected void report(final String message, final IWorkbenchPart part) { JDIDebugUIPlugin.getStandardDisplay().asyncExec(new Runnable() { public void run() { @SuppressWarnings("cast") IEditorStatusLine statusLine = (IEditorStatusLine) part.getAdapter(IEditorStatusLine.class); if (statusLine != null) { if (message != null) { statusLine.setMessage(true, message, null); } else { statusLine.setMessage(true, null, null); } } if (message != null && JDIDebugUIPlugin.getActiveWorkbenchShell() != null) { JDIDebugUIPlugin.getActiveWorkbenchShell().getDisplay().beep(); } } }); } protected IType getType(ITextSelection selection) { IMember member = ActionDelegateHelper.getDefault().getCurrentMember(selection); IType type = null; if (member instanceof IType) { type = (IType) member; } else if (member != null) { type = member.getDeclaringType(); } // bug 52385: we don't want local and anonymous types from compilation // unit, // we are getting 'not-always-correct' names for them. try { while (type != null && !type.isBinary() && type.isLocal()) { type = type.getDeclaringType(); } } catch (JavaModelException e) { JDIDebugUIPlugin.log(e); } return type; } /* * (non-Javadoc) * * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#toggleLineBreakpoints(IWorkbenchPart, * ISelection) */ public void toggleLineBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException { toggleLineBreakpoints(part, selection, false); } public void toggleLineBreakpoints(final IWorkbenchPart part, final ISelection selection, final boolean bestMatch) { Job job = new Job("Toggle Line Breakpoint") { //$NON-NLS-1$ @Override public boolean belongsTo(Object family) { return family == TOGGLE_BREAKPOINT_FAMILY; } @Override protected IStatus run(IProgressMonitor monitor) { if (selection instanceof ITextSelection) { if (monitor.isCanceled()) { return Status.CANCEL_STATUS; } report(null, part); IEditorPart editorPart = (IEditorPart) part; ITextSelection textSelection = (ITextSelection) selection; IType type = getType(textSelection); IEditorInput editorInput = editorPart.getEditorInput(); IDocumentProvider documentProvider = ((ITextEditor) editorPart).getDocumentProvider(); if (documentProvider == null) { return Status.CANCEL_STATUS; } IDocument document = documentProvider.getDocument(editorInput); int lineNumber = textSelection.getStartLine() + 1; int offset = textSelection.getOffset(); try { if (type == null) { @SuppressWarnings("cast") IClassFile classFile = (IClassFile) editorInput.getAdapter(IClassFile.class); if (classFile != null) { type = classFile.getType(); // bug 34856 - if this is an inner type, ensure // the breakpoint is not // being added to the outer type if (type.getDeclaringType() != null) { ISourceRange sourceRange = type.getSourceRange(); int start = sourceRange.getOffset(); int end = start + sourceRange.getLength(); if (offset < start || offset > end) { // not in the inner type IStatusLineManager statusLine = editorPart.getEditorSite().getActionBars().getStatusLineManager(); statusLine.setErrorMessage(NLS.bind("Breakpoints can only be created within the type associated with the editor: {0}.", new String[] { type.getTypeQualifiedName() })); Display.getCurrent().beep(); return Status.OK_STATUS; } } } } String typeName = null; IResource resource = null; Map<String, Object> attributes = new HashMap<String, Object>(10); if (type == null) { resource = getResource(editorPart); if (editorPart instanceof ITextEditor) { ModuleNode node = getModuleNode((ITextEditor) editorPart); if (node != null) { // can be null if not on build path for (ClassNode clazz : (Iterable<ClassNode>) node.getClasses()) { int begin = clazz.getStart(); int end = clazz.getEnd(); if (offset >= begin && offset <= end && !clazz.isInterface()) { typeName = clazz.getName(); break; } } } } if(typeName == null) { ICompilationUnit unit = JavaCore.createCompilationUnitFrom((IFile) resource); if(unit != null) { IType[] types = unit.getAllTypes(); for (int i = 0; i < types.length; i++) { int begin = types[i].getSourceRange().getOffset(); int end = begin + types[i].getSourceRange().getLength(); if (offset >= begin && offset <= end && !types[i].isInterface()) { typeName = types[i].getPackageFragment().getElementName() + "." + types[i].getTypeQualifiedName(); //$NON-NLS-1$ break; } } } } } else { typeName = type.getFullyQualifiedName(); int index = typeName.indexOf('$'); if (index >= 0) { typeName = typeName.substring(0, index); } resource = BreakpointUtils.getBreakpointResource(type); try { IRegion line = document.getLineInformation(lineNumber - 1); int start = line.getOffset(); int end = start + line.getLength() - 1; BreakpointUtils.addJavaBreakpointAttributesWithMemberDetails(attributes, type, start, end); } catch (BadLocationException ble) { JDIDebugUIPlugin.log(ble); } } if (typeName != null && resource != null) { IJavaLineBreakpoint existingBreakpoint = JDIDebugModel.lineBreakpointExists(resource, typeName, lineNumber); if (existingBreakpoint != null) { removeBreakpoint(existingBreakpoint, true); return Status.OK_STATUS; } createLineBreakpoint(resource, typeName, offset, lineNumber, -1, -1, 0, true, attributes, document, bestMatch, type, editorPart); } } catch (CoreException ce) { return ce.getStatus(); } } return Status.OK_STATUS; } }; job.schedule(); } private void createLineBreakpoint(IResource resource, String typeName, int offset, int lineNumber, int charStart, int charEnd, int hitCount, boolean register, Map<String, Object> attributes, IDocument document, boolean bestMatch, IType type, IEditorPart editorPart) throws CoreException { IJavaLineBreakpoint breakpoint = JDIDebugModel.createLineBreakpoint(resource, typeName, lineNumber, charStart, charEnd, hitCount, register, attributes); new BreakpointLocationVerifierJob(breakpoint, lineNumber, typeName, type, resource, editorPart).schedule(); } public boolean canToggleLineBreakpoints(IWorkbenchPart part, ISelection selection) { return selection instanceof ITextSelection; } public void toggleMethodBreakpoints(final IWorkbenchPart part, final ISelection finalSelection) { } private void removeBreakpoint(IBreakpoint breakpoint, boolean delete) throws CoreException { DebugPlugin.getDefault().getBreakpointManager().removeBreakpoint(breakpoint, delete); } public boolean canToggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) { return false; } protected ModuleNode getModuleNode(ITextEditor editor) throws CoreException { IEditorInput editorInput = editor.getEditorInput(); @SuppressWarnings("cast") ICompilationUnit unit = (ICompilationUnit) editorInput.getAdapter(ICompilationUnit.class); if (unit == null) { @SuppressWarnings("cast") IFile file = (IFile) editorInput.getAdapter(IFile.class); if (file != null) { unit = JavaCore.createCompilationUnitFrom(file); } } if (! (unit instanceof GroovyCompilationUnit)) { throw new CoreException(Status.CANCEL_STATUS); } return ((GroovyCompilationUnit) unit).getModuleNode(); } public void toggleWatchpoints(final IWorkbenchPart part, final ISelection finalSelection) { } protected static IResource getResource(IEditorPart editor) { IEditorInput editorInput = editor.getEditorInput(); @SuppressWarnings("cast") IResource resource = (IFile) editorInput.getAdapter(IFile.class); if (resource == null) { resource = ResourcesPlugin.getWorkspace().getRoot(); } return resource; } public boolean canToggleWatchpoints(IWorkbenchPart part, ISelection selection) { return false; } public void toggleBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException { toggleLineBreakpoints(part, selection, true); } public boolean canToggleBreakpoints(IWorkbenchPart part, ISelection selection) { return canToggleLineBreakpoints(part, selection); } }