blob: 29cbe612beb5626eafae2538b27e993dc6d3c65f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.debug.internal.ui;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.debug.core.model.IThread;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
/**
* This class tracks instruction pointer contexts for all active debug targets and threads
* in the current workbench. There should only ever be one instance of this class, obtained
* via 'getDefault()'.
*/
public class InstructionPointerManager {
/**
* The singleton instance of this class.
*/
private static InstructionPointerManager fgDefault;
/**
* Mapping of IDebugTarget objects to (mappings of IThread objects to lists of instruction
* pointer contexts).
*/
private Map fDebugTargetMap;
/**
* Clients must not instantiate this class.
*/
private InstructionPointerManager() {
fDebugTargetMap = new HashMap();
}
/**
* Return the singleton instance of this class, creating it if necessary.
*/
public static InstructionPointerManager getDefault() {
if (fgDefault == null) {
fgDefault = new InstructionPointerManager();
}
return fgDefault;
}
/**
* Add an instruction pointer annotation in the specified editor for the
* specified stack frame.
*/
public void addAnnotation(ITextEditor textEditor, IStackFrame frame, Annotation annotation) {
IDocumentProvider docProvider = textEditor.getDocumentProvider();
IEditorInput editorInput = textEditor.getEditorInput();
// If there is no annotation model, there's nothing more to do
IAnnotationModel annModel = docProvider.getAnnotationModel(editorInput);
if (annModel == null) {
return;
}
// Create the Position object that specifies a location for the annotation
Position position = null;
int charStart = -1;
int length = -1;
try {
charStart = frame.getCharStart();
length = frame.getCharEnd() - charStart;
} catch (DebugException de) {
}
if (charStart < 0) {
IDocument doc = docProvider.getDocument(editorInput);
if (doc == null) {
return;
}
try {
int lineNumber = frame.getLineNumber() - 1;
IRegion region = doc.getLineInformation(lineNumber);
charStart = region.getOffset();
length = region.getLength();
} catch (BadLocationException ble) {
return;
} catch (DebugException de) {
return;
}
}
if (charStart < 0) {
return;
}
position = new Position(charStart, length);
// Add the annotation at the position to the editor's annotation model.
annModel.removeAnnotation(annotation);
annModel.addAnnotation(annotation, position);
// Retrieve the list of instruction pointer contexts
IDebugTarget debugTarget = frame.getDebugTarget();
Map threadMap = (Map) fDebugTargetMap.get(debugTarget);
if (threadMap == null) {
threadMap = new HashMap();
fDebugTargetMap.put(debugTarget, threadMap);
}
IThread thread = frame.getThread();
List contextList = (List) threadMap.get(thread);
if (contextList == null) {
contextList = new ArrayList();
threadMap.put(thread, contextList);
}
// Create a context object & add it to the list
InstructionPointerContext context = new InstructionPointerContext(textEditor, annotation);
contextList.remove(context);
contextList.add(context);
}
/**
* Remove all annotations associated with the specified debug target that this class
* is tracking.
*/
public void removeAnnotations(IDebugTarget debugTarget) {
// Retrieve the mapping of threads to context lists
Map threadMap = (Map) fDebugTargetMap.get(debugTarget);
if (threadMap == null) {
return;
}
// Remove annotations for all threads associated with the debug target
Object[] threads = threadMap.keySet().toArray();
for (int i = 0; i < threads.length; i++) {
IThread thread = (IThread) threads[i];
removeAnnotations(thread, threadMap);
}
// Remove the entry for the debug target
fDebugTargetMap.remove(debugTarget);
}
/**
* Remove all annotations associated with the specified thread that this class
* is tracking.
*/
public void removeAnnotations(IThread thread) {
// Retrieve the thread map
IDebugTarget debugTarget = thread.getDebugTarget();
Map threadMap = (Map) fDebugTargetMap.get(debugTarget);
if (threadMap == null) {
return;
}
// Remove all annotations for the thread
removeAnnotations(thread, threadMap);
}
/**
* Remove all annotations associated with the specified thread.
*/
private void removeAnnotations(IThread thread, Map threadMap) {
// Retrieve the context list and remove each corresponding annotation
List contextList = (List) threadMap.get(thread);
if (contextList != null) {
Iterator contextIterator = contextList.iterator();
while (contextIterator.hasNext()) {
InstructionPointerContext context = (InstructionPointerContext) contextIterator.next();
removeAnnotation(context.getTextEditor(), context.getAnnotation());
}
}
// Remove the thread map
threadMap.remove(thread);
}
/**
* Remove the specified annotation from the specified text editor.
*/
private void removeAnnotation(ITextEditor textEditor, Annotation annotation) {
IDocumentProvider docProvider = textEditor.getDocumentProvider();
if (docProvider != null) {
IAnnotationModel annotationModel = docProvider.getAnnotationModel(textEditor.getEditorInput());
if (annotationModel != null) {
annotationModel.removeAnnotation(annotation);
}
}
}
}