/*******************************************************************************
* Copyright (c) 2014, 2015 Willink Transformations 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:
* R.Dvorak and others - QVTo debugger framework
* E.D.Willink - revised API for OCL debugger framework
*******************************************************************************/
package org.eclipse.ocl.examples.debug.vm.ui.actions;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.model.ILineBreakpoint;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.ocl.examples.debug.launching.OCLDebuggableRunnerFactory;
import org.eclipse.ocl.examples.debug.vm.ui.DebugVMUIPlugin;
import org.eclipse.ocl.examples.debug.vm.utils.CompiledUnit;
import org.eclipse.ocl.examples.debug.vm.utils.LineNumberProvider;
import org.eclipse.ocl.pivot.Element;
import org.eclipse.ocl.pivot.Model;
import org.eclipse.ocl.pivot.resource.ASResource;
import org.eclipse.ocl.xtext.base.cs2as.CS2AS;
import org.eclipse.ocl.xtext.base.utilities.BaseCSResource;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.IEditorStatusLine;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.ui.editor.model.XtextDocument;
import org.eclipse.xtext.util.concurrent.IUnitOfWork;
class BreakpointLocationVerifier {
private static @NonNull LineNumberProvider getLineNumberProvider(final @NonNull IDocument doc) {
return new LineNumberProvider() {
public int getLineNumber(int offset) {
try {
return doc.getLineOfOffset(offset) + 1;
} catch (BadLocationException e) {
return -1;
}
}
public int getLineEnd(int lineNumber) {
try {
IRegion lineInfo = doc.getLineInformation(lineNumber);
return lineInfo.getOffset() + lineInfo.getLength();
} catch (BadLocationException e) {
return -1;
}
}
public int getLineCount() {
return doc.getNumberOfLines();
}
};
}
// private static final int GET_AST_TIMEOUT = 10 * 1000;
private final ILineBreakpoint fBreakpoint;
private final ITextEditor fEditor;
private final String fInvalidLocationMessage;
BreakpointLocationVerifier(ITextEditor editor, ILineBreakpoint breakpoint, String invalidLocationMessage) {
if(editor == null || breakpoint == null || invalidLocationMessage == null) {
throw new IllegalArgumentException();
}
fEditor = editor;
fBreakpoint = breakpoint;
fInvalidLocationMessage = invalidLocationMessage;
}
IStatus run() {
IStatus status = checkBreakpointableElements();
if(!status.isOK()) {
if (fBreakpoint != null) {
try {
DebugPlugin.getDefault().getBreakpointManager().removeBreakpoint(fBreakpoint, true);
} catch (CoreException e) {
DebugVMUIPlugin.log(e.getStatus());
}
}
}
return status;
}
private IStatus checkBreakpointableElements() {
int lineNumber;
try {
lineNumber = fBreakpoint.getLineNumber();
} catch (CoreException e) {
return e.getStatus();
}
IDocumentProvider docProvider = fEditor.getDocumentProvider();
if(docProvider == null) {
return canceled();
}
IDocument doc = docProvider.getDocument(fEditor.getEditorInput());
if(doc == null) {
return canceled();
}
Model root = ((XtextDocument)doc).readOnly(new IUnitOfWork<Model, XtextResource>()
{
@Override
public Model exec(@Nullable XtextResource state) throws Exception {
if (state instanceof BaseCSResource) {
BaseCSResource csResource = (BaseCSResource)state;
CS2AS cs2as = csResource.findCS2AS();
if (cs2as != null) {
ASResource asResource = cs2as.getASResource();
if ((asResource != null) && (asResource.getContents().size() > 0)) {
EObject eObject = asResource.getContents().get(0);
if (eObject instanceof Model) {
return (Model)eObject;
}
}
}
}
return null;
}
});
CompiledUnit compilationUnit = root != null ? new CompiledUnit(root) : null;
if(compilationUnit == null) {
return DebugVMUIPlugin.createErrorStatus("Failed to obtain AST"); //$NON-NLS-1$
}
List<Element> elements = OCLDebuggableRunnerFactory.validBreakpointLocator
.getBreakpointableElementsForLine(compilationUnit, getLineNumberProvider(doc), lineNumber);
if (elements.isEmpty()) {
report(NLS.bind(fInvalidLocationMessage, new Integer(lineNumber)));
return canceled();
}
return Status.OK_STATUS;
}
/**
* Reports any status to the current active workbench shell
* @param message the message to display
*/
protected void report(final String message) {
DebugVMUIPlugin.getStandardDisplay().asyncExec(new Runnable() {
public void run() {
@Nullable IEditorStatusLine statusLine = (IEditorStatusLine) fEditor.getAdapter(IEditorStatusLine.class);
if (statusLine != null) {
statusLine.setMessage(true, message, null);
}
if (message != null && DebugVMUIPlugin.getActiveWorkbenchShell() != null) {
Display.getCurrent().beep();
}
}
});
}
private IStatus canceled() {
return DebugVMUIPlugin.createStatus(IStatus.CANCEL, fInvalidLocationMessage);
}
}