blob: b4deef530e1e03aae1091f4ea613b9f2231d2239 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 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.sourcelookup;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IDebugEventSetListener;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IDebugElement;
import org.eclipse.debug.core.model.ISourceLocator;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.debug.core.model.IThread;
import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupDirector;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.IDebugHelpContextIds;
import org.eclipse.debug.internal.ui.views.launch.LaunchView;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugModelPresentation;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.debug.ui.sourcelookup.SourceLookupDialog;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.resource.JFaceColors;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IReusableEditor;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
/**
* Editor for when source is not found. Shows the source name and has
* a button to add new containers.
* Editor ID: IInternalDebugUIConstants.ID_COMMON_SOURCE_NOT_FOUND_EDITOR = org.eclipse.debug.ui.sourcelookup.CommonSourceNotFoundEditor
*
* May be subclassed if a debugger requires additional buttons on the editor. For example,
* a button may be added if the user has the additional option of using generated source
* for debugging.
*
* @see AbstractSourceLookupDirector
* @see CommonSourceNotFoundEditorInput
* @since 3.0
*/
public class CommonSourceNotFoundEditor extends EditorPart implements IReusableEditor, IDebugEventSetListener {
/**
* Text widgets used for this editor
*/
private Text fText;
/**
* object for which the source is showing for (i.e., stackframe, breakpoint)
*/
protected Object fObject;
/**
* @see org.eclipse.ui.IEditorPart#doSave(IProgressMonitor)
*/
public void doSave(IProgressMonitor monitor) {
}
/**
* @see org.eclipse.ui.IEditorPart#doSaveAs()
*/
public void doSaveAs() {
}
/**
* @see org.eclipse.ui.IEditorPart#gotoMarker(IMarker)
*/
public void gotoMarker(IMarker marker) {
}
/**
* @see org.eclipse.ui.IEditorPart#init(IEditorSite, IEditorInput)
*/
public void init(IEditorSite site, IEditorInput input) throws PartInitException {
setSite(site);
setInput(input);
DebugPlugin.getDefault().addDebugEventListener(this);
}
/**
* @see org.eclipse.ui.IEditorPart#isDirty()
*/
public boolean isDirty() {
return false;
}
/**
* @see org.eclipse.ui.IEditorPart#isSaveAsAllowed()
*/
public boolean isSaveAsAllowed() {
return false;
}
/**
* @see org.eclipse.ui.IWorkbenchPart#createPartControl(Composite)
*/
public void createPartControl(Composite parent) {
GridLayout topLayout = new GridLayout();
GridData data = new GridData();
topLayout.numColumns = 1;
topLayout.verticalSpacing = 10;
parent.setLayout(topLayout);
parent.setLayoutData(data);
parent.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
fText = new Text(parent,SWT.READ_ONLY|SWT.WRAP);
fText.setForeground(JFaceColors.getErrorText(fText.getDisplay()));
fText.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
if (getEditorInput() != null) {
setInput(getEditorInput());
}
Button button = new Button(parent, SWT.PUSH);
data = new GridData();
data.grabExcessHorizontalSpace = false;
data.grabExcessVerticalSpace = false;
data.heightHint = 50;
data.widthHint=50;
button.setData(data);
button.setText(SourceLookupUIMessages.addSourceLocation_addButton2); //$NON-NLS-1$
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent evt) {
buttonSelected();
}
});
Dialog.applyDialogFont(parent);
PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, IDebugHelpContextIds.NO_SOURCE_EDITOR);
}
/**
* Handles the event when the "add source container" button is selected.
* Displays the <code>EditSourceLookupPathDialog</code> so the user
* can add additional source containers that should be searched.
*/
private void buttonSelected(){
ISourceLocator locator = null;
ILaunch launch = null;
IAdaptable selection = DebugUITools.getDebugContext();
if(selection == null) return;
if (selection.getAdapter(ILaunch.class) != null ) {
launch = (ILaunch) selection.getAdapter(ILaunch.class);
locator = launch.getSourceLocator();
}
else if (selection.getAdapter(IDebugElement.class) != null ) {
launch = ((IDebugElement)selection.getAdapter(IDebugElement.class)).getLaunch();
locator = launch.getSourceLocator();
}
else return; //should not occur
if (locator == null || !(locator instanceof AbstractSourceLookupDirector))
return;
final SourceLookupDialog dialog =
new SourceLookupDialog(DebugUIPlugin.getShell(),(AbstractSourceLookupDirector) locator);
int result = dialog.open();
if(result == Window.OK) {
resetEditor();
}
}
/**
* Clears the (source not found) editor inputs associated with the stack and
* opening the editor again, if the item is not a stackframe. A marker will be added
* and the editor will be told to scroll to the marker.
*
* If it is a stackframe, the launch view will pick up the change event and open a new
* editor automatically.
*
*/
public void resetEditor()
{
fireChangeEventsOnStack();
if(fObject instanceof IStackFrame) {
return; //launch view will pick up from here
}
// close this editor and open a new editor
final int lineNumber = getLineNumber();
Runnable open = new Runnable() {
public void run() {
IWorkbenchWindow dwindow= DebugUIPlugin.getActiveWorkbenchWindow();
if (dwindow != null) {
IWorkbenchPage page= dwindow.getActivePage();
if (page != null) {
IDebugModelPresentation modelPres = DebugUITools.newDebugModelPresentation();
IEditorInput input = modelPres.getEditorInput(fObject);
if (input != null) {
String id = modelPres.getEditorId(input, fObject);
if (id != null) {
try {
IEditorPart editorPart = page.openEditor(input, id);
if (editorPart instanceof ITextEditor && lineNumber >= 0) {
// position to line number
ITextEditor textEditor = (ITextEditor) editorPart;
IRegion region= getLineInformation(textEditor, lineNumber);
if (region != null) {
textEditor.selectAndReveal(region.getOffset(), 0);
}
}
} catch (PartInitException e1) {
}
}
}
modelPres.dispose();
}
}
}
};
closeEditor();
// get new editor input
DebugUIPlugin.getStandardDisplay().asyncExec(open);
}
/**
* Returns the line information for the given line in the given editor
*/
private IRegion getLineInformation(ITextEditor editor, int lineNumber) {
IDocumentProvider provider= editor.getDocumentProvider();
IEditorInput input= editor.getEditorInput();
try {
provider.connect(input);
} catch (CoreException e) {
return null;
}
try {
IDocument document= provider.getDocument(input);
if (document != null)
return document.getLineInformation(lineNumber);
} catch (BadLocationException e) {
} finally {
provider.disconnect(input);
}
return null;
}
/**
* Returns the line number associated with the breakpoint (marker).
* @return the line number to scroll to
*/
protected int getLineNumber(){
int line = -1;
if(fObject instanceof IMarker) {
try{
line=((Integer)((IMarker)fObject).getAttribute(IMarker.LINE_NUMBER)).intValue();
} catch(CoreException e){}
}
return line;
}
/**
* @see org.eclipse.ui.IWorkbenchPart#setFocus()
*/
public void setFocus() {
if (fText != null) {
fText.setFocus();
}
}
/**
* @see IReusableEditor#setInput(org.eclipse.ui.IEditorInput)
*/
public void setInput(IEditorInput input) {
super.setInput(input);
if(input instanceof CommonSourceNotFoundEditorInput) {
fObject = ((CommonSourceNotFoundEditorInput)input).getObject();
}
setPartName(input.getName());
if (fText != null) {
fText.setText(input.getToolTipText()+"\n"); //$NON-NLS-1$
}
}
/**
* Fires change event(s) to clear the source file history of the items in the stack.
*/
protected void fireChangeEventsOnStack(){
if(fObject instanceof IStackFrame) {
fireChangeEvent(DebugEvent.CONTENT, (IStackFrame)fObject);
} else if(fObject instanceof IDebugElement) { //loop through all threads and clear the cached source files
try{
IThread[] threads =((IDebugElement)fObject).getDebugTarget().getThreads();
for(int i=0; i< threads.length; i++)
{
fireChangeEvent(DebugEvent.CONTENT, threads[i].getTopStackFrame());
}
} catch(DebugException e){}
}
}
/**
* Fire a debug change event with detail
* @param detail @see DebugEvent
*/
public void fireChangeEvent(int detail, IDebugElement source) {
fireEvent(new DebugEvent(source, DebugEvent.CHANGE, detail));
}
/**
* Fire a debug event
*/
private void fireEvent(DebugEvent event) {
if(DebugPlugin.getDefault() != null)
DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] {event});
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.IDebugEventSetListener#handleDebugEvents(org.eclipse.debug.core.DebugEvent[])
*/
public void handleDebugEvents(DebugEvent[] events) {
for (int i = 0; i < events.length; i++) {
DebugEvent event = events[i];
Object source= event.getSource();
switch (event.getKind()) {
case DebugEvent.TERMINATE :
if(checkIfEditorShouldClose(source))
closeEditor();
break;
case DebugEvent.CHANGE :
if(!source.equals(fObject))
return;
// Trigger a selectionChange event
IWorkbenchWindow window= DebugUIPlugin.getActiveWorkbenchWindow();
if (window == null) {
return;
}
IWorkbenchPage p= window.getActivePage();
if (p == null) {
return;
}
IViewPart fLaunchView= p.findView(IDebugUIConstants.ID_DEBUG_VIEW);
if (fLaunchView instanceof ISelectionChangedListener) {
ISelection fSelection = ((LaunchView)fLaunchView).getViewer().getSelection();
// To clear the stackframe stored in the launchView
((LaunchView)fLaunchView).clearSourceSelection(((IStackFrame)source).getThread());
((LaunchView)fLaunchView).getViewer().setSelection(fSelection, true);
}
break;
}
}
}
/**
* Checks if the source of the terminate event is associated with this editor
* object.
* @param source the source of the event
* @return true if the <code>source</code> is related to this editor, false otherwise
*/
protected boolean checkIfEditorShouldClose(Object source) {
//Make sure terminate event is for me
if (fObject instanceof IDebugElement && source instanceof IDebugElement) {
IDebugElement element = (IDebugElement)fObject;
IDebugElement sourceElement = (IDebugElement)source;
return sourceElement.equals(element.getDebugTarget());
}
return false;
}
/**
* Closes this editor.
*/
protected void closeEditor()
{
final IEditorPart editor = this;
DebugUIPlugin.getStandardDisplay().syncExec(
new Runnable() {
public void run() {
IWorkbenchWindow activeWorkbenchWindow = DebugUIPlugin.getActiveWorkbenchWindow();
if (activeWorkbenchWindow != null) {
IWorkbenchPage activePage = activeWorkbenchWindow.getActivePage();
if (activePage != null) {
activePage.closeEditor(editor,false);
}
}
}
});
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchPart#dispose()
*/
public void dispose() {
DebugPlugin.getDefault().removeDebugEventListener(this);
super.dispose();
}
}