001: package de.loskutov.bco.editors;
002:
003: import java.text.MessageFormat;
004: import java.util.HashMap;
005: import java.util.Iterator;
006: import java.util.List;
007: import java.util.Map;
008:
009: import org.eclipse.core.resources.IResource;
010: import org.eclipse.core.resources.ResourcesPlugin;
011: import org.eclipse.core.runtime.CoreException;
012: import org.eclipse.core.runtime.IAdaptable;
013: import org.eclipse.core.runtime.IProgressMonitor;
014: import org.eclipse.core.runtime.IStatus;
015: import org.eclipse.core.runtime.Status;
016: import org.eclipse.core.runtime.jobs.Job;
017: import org.eclipse.debug.core.DebugPlugin;
018: import org.eclipse.debug.core.IBreakpointManager;
019: import org.eclipse.debug.core.model.IBreakpoint;
020: import org.eclipse.jdt.core.Flags;
021: import org.eclipse.jdt.core.IClassFile;
022: import org.eclipse.jdt.core.IField;
023: import org.eclipse.jdt.core.IMember;
024: import org.eclipse.jdt.core.IMethod;
025: import org.eclipse.jdt.core.ISourceRange;
026: import org.eclipse.jdt.core.IType;
027: import org.eclipse.jdt.core.JavaModelException;
028: import org.eclipse.jdt.core.dom.CompilationUnit;
029: import org.eclipse.jdt.debug.core.IJavaBreakpoint;
030: import org.eclipse.jdt.debug.core.IJavaFieldVariable;
031: import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
032: import org.eclipse.jdt.debug.core.IJavaMethodBreakpoint;
033: import org.eclipse.jdt.debug.core.IJavaWatchpoint;
034: import org.eclipse.jdt.debug.core.JDIDebugModel;
035: import org.eclipse.jdt.internal.debug.core.JavaDebugUtils;
036: import org.eclipse.jdt.internal.debug.ui.BreakpointUtils;
037: import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
038: import org.eclipse.jdt.internal.debug.ui.actions.ActionMessages;
039: import org.eclipse.jdt.internal.debug.ui.actions.BreakpointFieldLocator;
040: import org.eclipse.jdt.internal.debug.ui.actions.BreakpointLocationVerifierJob;
041: import org.eclipse.jdt.internal.debug.ui.actions.BreakpointMethodLocator;
042: import org.eclipse.jdt.internal.debug.ui.actions.ToggleBreakpointAdapter;
043: import org.eclipse.jface.action.IStatusLineManager;
044: import org.eclipse.jface.text.BadLocationException;
045: import org.eclipse.jface.text.IDocument;
046: import org.eclipse.jface.text.IRegion;
047: import org.eclipse.jface.text.ITextSelection;
048: import org.eclipse.jface.viewers.ISelection;
049: import org.eclipse.jface.viewers.IStructuredSelection;
050: import org.eclipse.swt.widgets.Display;
051: import org.eclipse.ui.IEditorInput;
052: import org.eclipse.ui.IEditorPart;
053: import org.eclipse.ui.IWorkbenchPart;
054: import org.eclipse.ui.texteditor.IDocumentProvider;
055: import org.eclipse.ui.texteditor.ITextEditor;
056:
057: /**
058: * Extend ToggleBreakpointAdapter to allow us map source code lines to the bytecode lines
059: * TODO implement the mapping :)
060: * @author Andrei
061: *
062: */
063: public class BytecodeBreakpointAdapter extends ToggleBreakpointAdapter {
064:
065: public boolean canToggleBreakpoints(IWorkbenchPart part,
066: ISelection selection) {
067: // should work for us.
068: return super .canToggleBreakpoints(part, selection);
069: }
070:
071: public void toggleBreakpoints(IWorkbenchPart part,
072: ISelection selection) throws CoreException {
073: // should work for us.
074: super .toggleBreakpoints(part, selection);
075: }
076:
077: public boolean canToggleLineBreakpoints(IWorkbenchPart part,
078: ISelection selection) {
079: // should work for us.
080: return super .canToggleBreakpoints(part, selection);
081: }
082:
083: public boolean canToggleMethodBreakpoints(IWorkbenchPart part,
084: ISelection selection) {
085: // TODO should revisit, because it deals with IJavaElements in the selection
086: return super .canToggleMethodBreakpoints(part, selection);
087: }
088:
089: public boolean canToggleWatchpoints(IWorkbenchPart part,
090: ISelection selection) {
091: // TODO should revisit, because it deals with IJavaElements in the selection
092: return super .canToggleWatchpoints(part, selection);
093: }
094:
095: public void toggleLineBreakpoints(IWorkbenchPart part,
096: ISelection selection) throws CoreException {
097: // should work for us.
098: super .toggleLineBreakpoints(part, selection);
099: }
100:
101: public void toggleMethodBreakpoints(final IWorkbenchPart part,
102: final ISelection finalSelection) {
103: Job job = new Job("Toggle Method Breakpoints") { //$NON-NLS-1$
104: protected IStatus run(IProgressMonitor monitor) {
105: if (monitor.isCanceled()) {
106: return Status.CANCEL_STATUS;
107: }
108: if (isInterface(finalSelection)) {
109: report(ActionMessages.ToggleBreakpointAdapter_7,
110: part);
111: return Status.OK_STATUS;
112: }
113: try {
114: report(null, part);
115: ISelection selection = finalSelection;
116: selection = translateToMembers(part, selection);
117: ITextEditor textEditor = getTextEditor(part);
118: if (textEditor != null
119: && selection instanceof ITextSelection) {
120: ITextSelection textSelection = (ITextSelection) selection;
121: CompilationUnit compilationUnit = parseCompilationUnit(textEditor);
122: if (compilationUnit != null) {
123: BreakpointMethodLocator locator = new BreakpointMethodLocator(
124: textSelection.getOffset());
125: compilationUnit.accept(locator);
126: String methodName = locator.getMethodName();
127: if (methodName == null) {
128: report(
129: "Method breakpoints can only be added to concrete methods.",
130: part);
131: return Status.OK_STATUS;
132: }
133: String typeName = locator.getTypeName();
134: String methodSignature = locator
135: .getMethodSignature();
136: if (methodSignature == null) {
137: report(
138: ActionMessages.ManageMethodBreakpointActionDelegate_methodNonAvailable,
139: part);
140: return Status.OK_STATUS;
141: }
142: // check if this method breakpoint already
143: // exist. If yes, remove it, else create one
144: IJavaMethodBreakpoint existing = getMethodBreakpoint(
145: typeName, methodName,
146: methodSignature);
147: if (existing == null) {
148: createMethodBreakpoint(
149: getResource((IEditorPart) part),
150: typeName, methodName,
151: methodSignature, true, false,
152: false, -1, -1, -1, 0, true,
153: new HashMap(10));
154: } else {
155: removeBreakpoint(existing, true);
156: }
157: }
158: } else if (selection instanceof IStructuredSelection) {
159: IMethod[] members = getMethods((IStructuredSelection) selection);
160: if (members.length == 0) {
161: report(
162: ActionMessages.ToggleBreakpointAdapter_9,
163: part);
164: return Status.OK_STATUS;
165: }
166: for (int i = 0, length = members.length; i < length; i++) {
167: IMethod method = members[i];
168: IJavaBreakpoint breakpoint = getMethodBreakpoint(method);
169: if (breakpoint == null) {
170: // add breakpoint
171: int start = -1;
172: int end = -1;
173: ISourceRange range = method
174: .getNameRange();
175: if (range != null) {
176: start = range.getOffset();
177: end = start + range.getLength();
178: }
179: Map attributes = new HashMap(10);
180: BreakpointUtils
181: .addJavaBreakpointAttributes(
182: attributes, method);
183: IType type = method.getDeclaringType();
184: String methodSignature = method
185: .getSignature();
186: String methodName = method
187: .getElementName();
188: if (method.isConstructor()) {
189: methodName = "<init>"; //$NON-NLS-1$
190: if (type.isEnum()) {
191: methodSignature = "(Ljava.lang.String;I" + methodSignature.substring(1); //$NON-NLS-1$
192: }
193: }
194: if (!type.isBinary()) {
195: // resolve the type names
196: methodSignature = resolveMethodSignature(
197: type, methodSignature);
198: if (methodSignature == null) {
199: report(
200: ActionMessages.ManageMethodBreakpointActionDelegate_methodNonAvailable,
201: part);
202: return Status.OK_STATUS;
203: }
204: }
205: createMethodBreakpoint(BreakpointUtils
206: .getBreakpointResource(method),
207: type.getFullyQualifiedName(),
208: methodName, methodSignature,
209: true, false, false, -1, start,
210: end, 0, true, attributes);
211: } else {
212: // remove breakpoint
213: removeBreakpoint(breakpoint, true);
214: }
215: }
216: }
217: } catch (CoreException e) {
218: return e.getStatus();
219: }
220: return Status.OK_STATUS;
221: }
222: };
223: job.setSystem(true);
224: job.schedule();
225:
226: }
227:
228: public void toggleWatchpoints(final IWorkbenchPart part,
229: final ISelection finalSelection) {
230: Job job = new Job("Toggle Watchpoints") { //$NON-NLS-1$
231: protected IStatus run(IProgressMonitor monitor) {
232: if (monitor.isCanceled()) {
233: return Status.CANCEL_STATUS;
234: }
235: if (isInterface(finalSelection)) {
236: report(ActionMessages.ToggleBreakpointAdapter_5,
237: part);
238: return Status.OK_STATUS;
239: }
240: try {
241: report(null, part);
242: ISelection selection = finalSelection;
243: selection = translateToMembers(part, selection);
244: ITextEditor textEditor = getTextEditor(part);
245: boolean allowed = false;
246: if (textEditor != null
247: && selection instanceof ITextSelection) {
248: ITextSelection textSelection = (ITextSelection) selection;
249: CompilationUnit compilationUnit = parseCompilationUnit(textEditor);
250: if (compilationUnit != null) {
251: BreakpointFieldLocator locator = new BreakpointFieldLocator(
252: textSelection.getOffset());
253: compilationUnit.accept(locator);
254: String fieldName = locator.getFieldName();
255: if (fieldName == null) {
256: report(
257: "Watchpoints can only be added to field members.",
258: part);
259: return Status.OK_STATUS;
260: }
261: int idx = fieldName.indexOf("final"); //$NON-NLS-1$
262: if (!(idx > -1)
263: & !(fieldName.indexOf("static") > -1 & idx > -1)) { //$NON-NLS-1$
264: allowed = true;
265: }
266: String typeName = locator.getTypeName();
267: // check if the watchpoint already exists. If yes,
268: // remove it, else create one
269: IJavaWatchpoint existing = getWatchpoint(
270: typeName, fieldName);
271: if (existing == null) {
272: if (!allowed) {
273: report(
274: "You cannot create create watchpoints on final or static final members.",
275: part);
276: return Status.OK_STATUS;
277: }
278: createWatchpoint(
279: getResource((IEditorPart) part),
280: typeName, fieldName, -1, -1,
281: -1, 0, true, new HashMap(10));
282: } else {
283: removeBreakpoint(existing, true);
284: }
285: }
286: } else if (selection instanceof IStructuredSelection) {
287: List fields = getFields((IStructuredSelection) selection);
288: if (fields.isEmpty()) {
289: report(
290: ActionMessages.ToggleBreakpointAdapter_10,
291: part);
292: return Status.OK_STATUS;
293: }
294: Iterator theFields = fields.iterator();
295: while (theFields.hasNext()) {
296: Object element = theFields.next();
297: IField javaField = null;
298: IJavaFieldVariable var = null;
299: String typeName = null;
300: String fieldName = null;
301: if (element instanceof IField) {
302: javaField = (IField) element;
303: typeName = javaField.getDeclaringType()
304: .getFullyQualifiedName();
305: fieldName = javaField.getElementName();
306: int f = javaField.getFlags();
307: boolean fin = Flags.isFinal(f);
308: allowed = !fin
309: && !(Flags.isStatic(f) && fin);
310: } else if (element instanceof IJavaFieldVariable) {
311: var = (IJavaFieldVariable) element;
312: typeName = var.getDeclaringType()
313: .getName();
314: fieldName = var.getName();
315: allowed = !(var.isFinal() || var
316: .isStatic());
317: }
318: IJavaBreakpoint breakpoint = getWatchpoint(
319: typeName, fieldName);
320: if (breakpoint == null) {
321: if (!allowed) {
322: report(
323: "You cannot create create watchpoints on final or static final members.",
324: part);
325: return Status.OK_STATUS;
326: }
327: IResource resource = null;
328: int start = -1;
329: int end = -1;
330: Map attributes = new HashMap(10);
331: if (javaField == null) {
332: if (var != null) {
333: Object object = JavaDebugUtils
334: .resolveSourceElement(
335: var
336: .getJavaType(),
337: var.getLaunch());
338: if (object instanceof IAdaptable) {
339: IAdaptable adaptable = (IAdaptable) object;
340: resource = (IResource) adaptable
341: .getAdapter(IResource.class);
342: }
343: }
344: if (resource == null) {
345: resource = ResourcesPlugin
346: .getWorkspace()
347: .getRoot();
348: }
349: } else {
350: IType type = javaField
351: .getDeclaringType();
352: ISourceRange range = javaField
353: .getNameRange();
354: if (range != null) {
355: start = range.getOffset();
356: end = start + range.getLength();
357: }
358: BreakpointUtils
359: .addJavaBreakpointAttributes(
360: attributes,
361: javaField);
362: resource = BreakpointUtils
363: .getBreakpointResource(type);
364: }
365: createWatchpoint(resource, typeName,
366: fieldName, -1, start, end, 0,
367: true, attributes);
368: } else {
369: // remove breakpoint
370: removeBreakpoint(breakpoint, true);
371: }
372: }
373: }
374: } catch (CoreException e) {
375: return e.getStatus();
376: }
377: return Status.OK_STATUS;
378: }
379: };
380: job.setSystem(true);
381: job.schedule();
382: }
383:
384: /**
385: * Toggles a line breakpoint. This is also the method called by the keybinding for creating breakpoints
386: * @param part the currently active workbench part
387: * @param selection the current selection
388: * @param bestMatch if we should make a best match or not
389: */
390: public void toggleLineBreakpoints(final IWorkbenchPart part,
391: final ISelection selection, final boolean bestMatch) {
392: Job job = new Job("Toggle Line Breakpoint") { //$NON-NLS-1$
393: protected IStatus run(IProgressMonitor monitor) {
394: if (isInterface(selection)) {
395: report(ActionMessages.ToggleBreakpointAdapter_6,
396: part);
397: return Status.OK_STATUS;
398: }
399: ITextEditor editor = getTextEditor(part);
400: if (editor != null
401: && selection instanceof ITextSelection) {
402: if (monitor.isCanceled()) {
403: return Status.CANCEL_STATUS;
404: }
405: report(null, part);
406: ITextSelection textSelection = (ITextSelection) selection;
407: IType type = getType(textSelection);
408: int lineNumber = textSelection.getStartLine() + 1;
409: int offset = textSelection.getOffset();
410: try {
411: IEditorInput editorInput = editor
412: .getEditorInput();
413: IDocumentProvider documentProvider = editor
414: .getDocumentProvider();
415: if (documentProvider == null) {
416: return Status.CANCEL_STATUS;
417: }
418: IDocument document = documentProvider
419: .getDocument(editorInput);
420: if (type == null) {
421: IClassFile classFile = (IClassFile) editorInput
422: .getAdapter(IClassFile.class);
423: if (classFile != null) {
424: type = classFile.getType();
425: // bug 34856 - if this is an inner type, ensure
426: // the breakpoint is not
427: // being added to the outer type
428: if (type.getDeclaringType() != null) {
429: ISourceRange sourceRange = type
430: .getSourceRange();
431: int start = sourceRange.getOffset();
432: int end = start
433: + sourceRange.getLength();
434: if (offset < start || offset > end) {
435: // not in the inner type
436: IStatusLineManager statusLine = editor
437: .getEditorSite()
438: .getActionBars()
439: .getStatusLineManager();
440: statusLine
441: .setErrorMessage(MessageFormat
442: .format(
443: "Breakpoints can only be created within the type associated with the editor: {0}.",
444: new String[] { type
445: .getTypeQualifiedName() }));
446: Display.getCurrent().beep();
447: return Status.OK_STATUS;
448: }
449: }
450: }
451: }
452: String typeName = null;
453: IResource resource = null;
454: Map attributes = new HashMap(10);
455: if (type == null) {
456: resource = getResource(editor);
457: CompilationUnit unit = parseCompilationUnit(editor);
458: Iterator types = unit.types().iterator();
459: // TODO unreachable API
460: // while (types.hasNext()) {
461: // TypeDeclaration declaration = (TypeDeclaration) types.next();
462: // int begin = declaration.getStartPosition();
463: // int end = begin + declaration.getLength();
464: // if (offset >= begin && offset <= end && !declaration.isInterface()) {
465: // typeName = ValidBreakpointLocationLocator.computeTypeName(declaration);
466: // break;
467: // }
468: // }
469: } else {
470: typeName = type.getFullyQualifiedName();
471: int index = typeName.indexOf('$');
472: if (index >= 0) {
473: typeName = typeName.substring(0, index);
474: }
475: resource = BreakpointUtils
476: .getBreakpointResource(type);
477: try {
478: IRegion line = document
479: .getLineInformation(lineNumber - 1);
480: int start = line.getOffset();
481: int end = start + line.getLength() - 1;
482: BreakpointUtils
483: .addJavaBreakpointAttributesWithMemberDetails(
484: attributes, type,
485: start, end);
486: } catch (BadLocationException ble) {
487: JDIDebugUIPlugin.log(ble);
488: }
489: }
490: if (typeName != null && resource != null) {
491: IJavaLineBreakpoint existingBreakpoint = JDIDebugModel
492: .lineBreakpointExists(resource,
493: typeName, lineNumber);
494: if (existingBreakpoint != null) {
495: removeBreakpoint(existingBreakpoint,
496: true);
497: return Status.OK_STATUS;
498: }
499: createLineBreakpoint(resource, typeName,
500: lineNumber, -1, -1, 0, true,
501: attributes, document, bestMatch,
502: type, editor);
503: }
504: } catch (CoreException ce) {
505: return ce.getStatus();
506: }
507: }
508: return Status.OK_STATUS;
509: }
510: };
511: job.setSystem(true);
512: job.schedule();
513: }
514:
515: /**
516: * Returns any existing method breakpoint for the specified method or <code>null</code> if none.
517: *
518: * @param typeName fully qualified type name
519: * @param methodName method selector
520: * @param methodSignature method signature
521: * @return existing method or <code>null</code>
522: * @throws CoreException
523: */
524: protected IJavaMethodBreakpoint getMethodBreakpoint(
525: String typeName, String methodName, String methodSignature)
526: throws CoreException {
527: final IBreakpointManager breakpointManager = DebugPlugin
528: .getDefault().getBreakpointManager();
529: IBreakpoint[] breakpoints = breakpointManager
530: .getBreakpoints(JDIDebugModel.getPluginIdentifier());
531: for (int i = 0; i < breakpoints.length; i++) {
532: IBreakpoint breakpoint = breakpoints[i];
533: if (breakpoint instanceof IJavaMethodBreakpoint) {
534: final IJavaMethodBreakpoint methodBreakpoint = (IJavaMethodBreakpoint) breakpoint;
535: if (typeName.equals(methodBreakpoint.getTypeName())
536: && methodName.equals(methodBreakpoint
537: .getMethodName())
538: && methodSignature.equals(methodBreakpoint
539: .getMethodSignature())) {
540: return methodBreakpoint;
541: }
542: }
543: }
544: return null;
545: }
546:
547: /**
548: * Returns any existing watchpoint for the given field, or <code>null</code> if none.
549: *
550: * @param typeName fully qualified type name on which watchpoint may exist
551: * @param fieldName field name
552: * @return any existing watchpoint for the given field, or <code>null</code> if none
553: * @throws CoreException
554: */
555: protected IJavaWatchpoint getWatchpoint(String typeName,
556: String fieldName) throws CoreException {
557: IBreakpointManager breakpointManager = DebugPlugin.getDefault()
558: .getBreakpointManager();
559: IBreakpoint[] breakpoints = breakpointManager
560: .getBreakpoints(JDIDebugModel.getPluginIdentifier());
561: for (int i = 0; i < breakpoints.length; i++) {
562: IBreakpoint breakpoint = breakpoints[i];
563: if (breakpoint instanceof IJavaWatchpoint) {
564: IJavaWatchpoint watchpoint = (IJavaWatchpoint) breakpoint;
565: if (typeName.equals(watchpoint.getTypeName())
566: && fieldName.equals(watchpoint.getFieldName())) {
567: return watchpoint;
568: }
569: }
570: }
571: return null;
572: }
573:
574: protected void createMethodBreakpoint(IResource resource,
575: String typeName, String methodName, String methodSignature,
576: boolean entry, boolean exit, boolean nativeOnly,
577: int lineNumber, int charStart, int charEnd, int hitCount,
578: boolean register, Map attributes) throws CoreException {
579: JDIDebugModel.createMethodBreakpoint(resource, typeName,
580: methodName, methodSignature, entry, exit, nativeOnly,
581: lineNumber, charStart, charEnd, hitCount, register,
582: attributes);
583: }
584:
585: protected void createWatchpoint(IResource resource,
586: String typeName, String fieldName, int lineNumber,
587: int charStart, int charEnd, int hitCount, boolean register,
588: Map attributes) throws CoreException {
589: JDIDebugModel.createWatchpoint(resource, typeName, fieldName,
590: lineNumber, charStart, charEnd, hitCount, register,
591: attributes);
592: }
593:
594: protected void createLineBreakpoint(IResource resource,
595: String typeName, int lineNumber, int charStart,
596: int charEnd, int hitCount, boolean register,
597: Map attributes, IDocument document, boolean bestMatch,
598: IType type, IEditorPart editorPart) throws CoreException {
599: IJavaLineBreakpoint breakpoint = JDIDebugModel
600: .createLineBreakpoint(resource, typeName, lineNumber,
601: charStart, charEnd, hitCount, register,
602: attributes);
603: new BreakpointLocationVerifierJob(document, breakpoint,
604: lineNumber, bestMatch, typeName, type, resource,
605: editorPart).schedule();
606: }
607:
608: /**
609: * Removes the specified breakpoint
610: * @param breakpoint the breakpoint to remove
611: * @param delete if it should be deleted as well
612: * @throws CoreException
613: */
614: protected void removeBreakpoint(IBreakpoint breakpoint,
615: boolean delete) throws CoreException {
616: DebugPlugin.getDefault().getBreakpointManager()
617: .removeBreakpoint(breakpoint, delete);
618: }
619:
620: /**
621: * Returns if the structured selection is itself or is part of an interface
622: * @param selection the current selection
623: * @return true if the selection isor is part of an interface, false otherwise
624: * @since 3.2
625: */
626: protected boolean isInterface(ISelection selection) {
627: if (!selection.isEmpty()) {
628: try {
629: if (selection instanceof IStructuredSelection) {
630: IStructuredSelection ss = (IStructuredSelection) selection;
631: Iterator iterator = ss.iterator();
632: IType type = null;
633: Object obj = null;
634: while (iterator.hasNext()) {
635: obj = iterator.next();
636: if (obj instanceof IMember) {
637: type = ((IMember) obj).getDeclaringType();
638: }
639: if (type != null && type.isInterface()) {
640: return true;
641: }
642: }
643: } else if (selection instanceof ITextSelection) {
644: ITextSelection tsel = (ITextSelection) selection;
645: IType type = getType(tsel);
646: if (type != null && type.isInterface()) {
647: return true;
648: }
649: }
650: } catch (JavaModelException e) {
651: JDIDebugUIPlugin.log(e);
652: }
653: }
654: return false;
655: }
656: }
|