/*******************************************************************************
* Copyright (c) 2011 Mentor Graphics 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:
* Mentor Graphics - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.internal.ui.actions;
import java.math.BigInteger;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.IDeclaration;
import org.eclipse.cdt.core.model.IFunction;
import org.eclipse.cdt.core.model.IFunctionDeclaration;
import org.eclipse.cdt.core.model.IMethod;
import org.eclipse.cdt.core.model.ISourceRange;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.model.IVariable;
import org.eclipse.cdt.debug.core.model.ICFunctionBreakpoint;
import org.eclipse.cdt.debug.core.model.ICLineBreakpoint;
import org.eclipse.cdt.debug.core.model.ICWatchpoint;
import org.eclipse.cdt.debug.internal.ui.CDebugUIUtils;
import org.eclipse.cdt.debug.internal.ui.IInternalCDebugUIConstants;
import org.eclipse.cdt.debug.ui.CDebugUIPlugin;
import org.eclipse.cdt.internal.ui.util.ExternalEditorInput;
import org.eclipse.cdt.ui.CDTUITools;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.editors.text.ILocationProvider;
import org.eclipse.ui.texteditor.IEditorStatusLine;
import org.eclipse.ui.texteditor.ITextEditor;
abstract public class AbstractToggleBreakpointAdapter implements IToggleBreakpointsTargetExtension {
/* (non-Javadoc)
* @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#toggleLineBreakpoints(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
public void toggleLineBreakpoints( IWorkbenchPart part, ISelection selection ) throws CoreException {
String errorMessage = null;
if ( part instanceof ITextEditor ) {
ITextEditor textEditor = (ITextEditor)part;
IEditorInput input = textEditor.getEditorInput();
if ( input == null ) {
errorMessage = ActionMessages.getString( "ToggleBreakpointAdapter.Empty_editor_1" ); //$NON-NLS-1$
}
else {
IDocument document = textEditor.getDocumentProvider().getDocument( input );
if ( document == null ) {
errorMessage = ActionMessages.getString( "ToggleBreakpointAdapter.Missing_document_1" ); //$NON-NLS-1$
}
else {
IResource resource = getResource( textEditor );
if ( resource == null ) {
errorMessage = ActionMessages.getString( "ToggleBreakpointAdapter.Missing_resource_1" ); //$NON-NLS-1$
}
else {
BreakpointLocationVerifier bv = new BreakpointLocationVerifier();
int lineNumber = bv.getValidLineBreakpointLocation( document, ((ITextSelection)selection).getStartLine() );
if ( lineNumber == -1 ) {
errorMessage = ActionMessages.getString( "ToggleBreakpointAdapter.Invalid_line_1" ); //$NON-NLS-1$
}
else {
String sourceHandle = getSourceHandle( input );
ICLineBreakpoint breakpoint = findLineBreakpoint( sourceHandle, resource, lineNumber );
if ( breakpoint != null ) {
DebugPlugin.getDefault().getBreakpointManager().removeBreakpoint( breakpoint, true );
}
else {
createLineBreakpoint( sourceHandle, resource, lineNumber );
}
return;
}
}
}
}
}
else {
errorMessage = ActionMessages.getString( "RunToLineAdapter.Operation_is_not_supported_1" ); //$NON-NLS-1$
}
throw new CoreException(
new Status( IStatus.ERROR, CDebugUIPlugin.getUniqueIdentifier(), IInternalCDebugUIConstants.INTERNAL_ERROR, errorMessage, null ) );
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#canToggleLineBreakpoints(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
public boolean canToggleLineBreakpoints( IWorkbenchPart part, ISelection selection ) {
return (selection instanceof ITextSelection);
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#toggleMethodBreakpoints(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
public void toggleMethodBreakpoints( IWorkbenchPart part, ISelection selection ) throws CoreException {
ICElement element = getCElementFromSelection( part, selection );
if ( element instanceof IFunction || element instanceof IMethod ) {
toggleMethodBreakpoints0( (IDeclaration)element );
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#canToggleMethodBreakpoints(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
public boolean canToggleMethodBreakpoints( IWorkbenchPart part, ISelection selection ) {
ICElement element = getCElementFromSelection( part, selection );
return (element instanceof IFunction || element instanceof IMethod);
}
protected ICElement getCElementFromSelection( IWorkbenchPart part, ISelection selection ) {
if ( selection instanceof ITextSelection ) {
ITextSelection textSelection = (ITextSelection)selection;
String text = textSelection.getText();
if ( text != null ) {
if ( part instanceof ITextEditor ) {
ICElement editorElement = CDTUITools.getEditorInputCElement( ((ITextEditor)part).getEditorInput() );
if ( editorElement instanceof ITranslationUnit ) {
ITranslationUnit tu = (ITranslationUnit)editorElement;
try {
if ( tu.isStructureKnown() && tu.isConsistent() ) {
return tu.getElementAtOffset( textSelection.getOffset() );
}
}
catch( CModelException exc ) {
// ignored on purpose
}
}
}
else {
IResource resource = getResource( part );
if ( resource instanceof IFile ) {
ITranslationUnit tu = getTranslationUnit( (IFile)resource );
if ( tu != null ) {
try {
ICElement element = tu.getElement( text.trim() );
if ( element == null ) {
element = tu.getElementAtLine( textSelection.getStartLine() );
}
return element;
}
catch( CModelException e ) {
}
}
}
}
}
}
else if ( selection instanceof IStructuredSelection ) {
IStructuredSelection ss = (IStructuredSelection)selection;
if ( ss.size() == 1 ) {
Object object = ss.getFirstElement();
if ( object instanceof ICElement ) {
return (ICElement)object;
}
}
}
return null;
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#toggleWatchpoints(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
public void toggleWatchpoints( IWorkbenchPart part, ISelection selection ) throws CoreException {
IVariable variable = getVariableFromSelection( part, selection );
if ( variable != null ) {
toggleVariableWatchpoint( part, variable );
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#canToggleWatchpoints(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
public boolean canToggleWatchpoints( IWorkbenchPart part, ISelection selection ) {
return getVariableFromSelection( part, selection ) != null;
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension#canToggleBreakpoints(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
public boolean canToggleBreakpoints( IWorkbenchPart part, ISelection selection ) {
return ( canToggleLineBreakpoints( part, selection )
|| canToggleWatchpoints( part, selection )
|| canToggleMethodBreakpoints( part, selection ) );
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension#toggleBreakpoints(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
public void toggleBreakpoints( IWorkbenchPart part, ISelection selection ) throws CoreException {
if ( canToggleLineBreakpoints( part, selection ) ) {
toggleLineBreakpoints( part, selection );
}
else {
ICElement element = getCElementFromSelection( part, selection );
if ( element instanceof IFunction || element instanceof IMethod ) {
toggleMethodBreakpoints0( (IDeclaration)element );
}
else if ( element instanceof IVariable ) {
toggleVariableWatchpoint( part, (IVariable)element );
}
}
}
protected IVariable getVariableFromSelection( IWorkbenchPart part, ISelection selection ) {
ICElement element = getCElementFromSelection( part, selection );
if ( element instanceof IVariable ) {
return (IVariable)element;
}
return null;
}
protected void report( String message, IWorkbenchPart part ) {
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 && CDebugUIPlugin.getActiveWorkbenchShell() != null ) {
CDebugUIPlugin.getActiveWorkbenchShell().getDisplay().beep();
}
}
protected static IResource getResource( IWorkbenchPart part ) {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
if ( part instanceof IEditorPart ) {
IEditorInput editorInput = ((IEditorPart)part).getEditorInput();
IResource resource = null;
if ( editorInput instanceof IFileEditorInput ) {
resource = ((IFileEditorInput)editorInput).getFile();
}
else if ( editorInput instanceof ExternalEditorInput ) {
resource = ((ExternalEditorInput)editorInput).getMarkerResource();
}
if ( resource != null )
return resource;
/* This file is not in a project, let default case handle it */
ILocationProvider provider = (ILocationProvider)editorInput.getAdapter( ILocationProvider.class );
if ( provider != null ) {
IPath location = provider.getPath( editorInput );
if ( location != null ) {
IFile[] files = root.findFilesForLocationURI( URIUtil.toURI( location ) );
if ( files.length > 0 && files[0].isAccessible())
return files[0];
}
}
}
return root;
}
private String getSourceHandle( IEditorInput input ) throws CoreException {
return CDebugUIUtils.getEditorFilePath( input );
}
private void toggleVariableWatchpoint( IWorkbenchPart part, IVariable variable ) throws CoreException {
String sourceHandle = getSourceHandle( variable );
IResource resource = getElementResource( variable );
String expression = getVariableName( variable );
ICWatchpoint watchpoint = findWatchpoint( sourceHandle, resource, expression );
if ( watchpoint != null ) {
DebugPlugin.getDefault().getBreakpointManager().removeBreakpoint( watchpoint, true );
}
else {
AddWatchpointDialog dlg = new AddWatchpointDialog( part.getSite().getShell(), AddWatchpointActionDelegate.getMemorySpaceManagement() );
dlg.setExpression( expression );
if ( dlg.open() != Window.OK )
return;
expression = dlg.getExpression();
int lineNumber = -1;
int charStart = -1;
int charEnd = -1;
try {
ISourceRange sourceRange = variable.getSourceRange();
if ( sourceRange != null ) {
charStart = sourceRange.getStartPos();
charEnd = charStart + sourceRange.getLength();
if ( charEnd <= 0 ) {
charStart = -1;
charEnd = -1;
}
lineNumber = sourceRange.getStartLine();
}
}
catch( CModelException e ) {
DebugPlugin.log( e );
}
createWatchpoint(
sourceHandle,
resource,
charStart,
charEnd,
lineNumber,
dlg.getWriteAccess(),
dlg.getReadAccess(),
expression,
dlg.getMemorySpace(),
dlg.getRange() );
}
}
private String getSourceHandle( IDeclaration declaration ) {
ITranslationUnit tu = declaration.getTranslationUnit();
if ( tu != null ) {
IPath location = tu.getLocation();
if ( location != null ) {
return location.toOSString();
}
}
return ""; //$NON-NLS-1$
}
private IResource getElementResource( IDeclaration declaration ) {
return declaration.getUnderlyingResource();
}
private String getFunctionName( IFunction function ) {
String functionName = function.getElementName();
StringBuffer name = new StringBuffer( functionName );
ITranslationUnit tu = function.getTranslationUnit();
if ( tu != null && tu.isCXXLanguage() ) {
appendParameters( name, function );
}
return name.toString();
}
private String getMethodName( IMethod method ) {
StringBuffer name = new StringBuffer();
String methodName = method.getElementName();
ICElement parent = method.getParent();
while( parent != null
&& (parent.getElementType() == ICElement.C_NAMESPACE || parent.getElementType() == ICElement.C_CLASS
|| parent.getElementType() == ICElement.C_STRUCT || parent.getElementType() == ICElement.C_UNION) ) {
name.append( parent.getElementName() ).append( "::" ); //$NON-NLS-1$
parent = parent.getParent();
}
name.append( methodName );
appendParameters( name, method );
return name.toString();
}
private void appendParameters( StringBuffer sb, IFunctionDeclaration fd ) {
String[] params = fd.getParameterTypes();
sb.append( '(' );
for( int i = 0; i < params.length; ++i ) {
sb.append( params[i] );
if ( i != params.length - 1 )
sb.append( ',' );
}
sb.append( ')' );
}
private String getVariableName( IVariable variable ) {
return variable.getElementName();
}
private ITranslationUnit getTranslationUnit( IFile file ) {
Object element = CoreModel.getDefault().create( file );
if ( element instanceof ITranslationUnit ) {
return (ITranslationUnit)element;
}
return null;
}
private void toggleMethodBreakpoints0( IDeclaration declaration ) throws CoreException {
String sourceHandle = getSourceHandle( declaration );
IResource resource = getElementResource( declaration );
String functionName = (declaration instanceof IFunction) ? getFunctionName( (IFunction)declaration ) : getMethodName( (IMethod)declaration );
ICFunctionBreakpoint breakpoint = findFunctionBreakpoint( sourceHandle, resource, functionName );
if ( breakpoint != null ) {
DebugPlugin.getDefault().getBreakpointManager().removeBreakpoint( breakpoint, true );
}
else {
int lineNumber = -1;
int charStart = -1;
int charEnd = -1;
try {
ISourceRange sourceRange = declaration.getSourceRange();
if ( sourceRange != null ) {
charStart = sourceRange.getStartPos();
charEnd = charStart + sourceRange.getLength();
if ( charEnd <= 0 ) {
charStart = -1;
charEnd = -1;
}
lineNumber = sourceRange.getStartLine();
}
}
catch( CModelException e ) {
DebugPlugin.log( e );
}
createFunctionBreakpoint(
sourceHandle,
resource,
functionName,
charStart,
charEnd,
lineNumber );
}
}
protected abstract ICLineBreakpoint findLineBreakpoint( String sourceHandle, IResource resource, int lineNumber ) throws CoreException;
protected abstract void createLineBreakpoint( String sourceHandle, IResource resource, int lineNumber ) throws CoreException;
protected abstract ICFunctionBreakpoint findFunctionBreakpoint( String sourceHandle, IResource resource, String functionName ) throws CoreException;
protected abstract void createFunctionBreakpoint(
String sourceHandle,
IResource resource,
String functionName,
int charStart,
int charEnd,
int lineNumber ) throws CoreException;
protected abstract ICWatchpoint findWatchpoint( String sourceHandle, IResource resource, String expression ) throws CoreException;
protected abstract void createWatchpoint(
String sourceHandle,
IResource resource,
int charStart,
int charEnd,
int lineNumber,
boolean writeAccess,
boolean readAccess,
String expression,
String memorySpace,
BigInteger range ) throws CoreException;
}