/*******************************************************************************
* Copyright (c) 2010 R.Dvorak 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:
* Sergey Boyko - initial API and implementation
*******************************************************************************/
package org.eclipse.m2m.internal.qvt.oml.debug.ui.actions;
import java.util.Iterator;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IDebugElement;
import org.eclipse.debug.core.model.IVariable;
import org.eclipse.debug.core.model.IWatchExpression;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugModelPresentation;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.m2m.qvt.oml.debug.core.QVTODebugCore;
import org.eclipse.m2m.qvt.oml.debug.core.QVTOVariable;
import org.eclipse.ui.IEditorActionDelegate;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.texteditor.ITextEditor;
/**
* Mostly identical to WatchAction from JDT
*/
public class QVTOWatchAction implements IPartListener, IWorkbenchWindowActionDelegate, IEditorActionDelegate{
private IAction fAction;
private IWorkbenchPart fTargetPart;
private IWorkbenchWindow fWindow;
private Object fSelection;
private IRegion fRegion;
/**
* The new target part to use with the evaluation completes.
*/
private IWorkbenchPart fNewTargetPart= null;
/**
* Used to resolve editor input for selected stack frame
*/
private IDebugModelPresentation fPresentation;
public QVTOWatchAction() {
super();
}
private void run() {
Object selectedObject= fSelection;
if (selectedObject instanceof IStructuredSelection) {
IStructuredSelection selection = (IStructuredSelection) selectedObject;
Iterator<?> elements = selection.iterator();
while (elements.hasNext()) {
try {
createWatchExpression(((IVariable) elements.next()).getName());
}
catch (DebugException e) {
QVTODebugCore.log(e);
return;
}
}
showExpressionView();
}
else if (selectedObject instanceof String) {
createWatchExpression((String) selectedObject);
showExpressionView();
}
}
/**
* Make the expression view visible or open one
* if required.
*/
private void showExpressionView() {
if (getTargetPart().getSite().getId().equals(IDebugUIConstants.ID_EXPRESSION_VIEW)) {
return;
}
IWorkbenchPage page = getActivePage();
if (page != null) {
IViewPart part = page.findView(IDebugUIConstants.ID_EXPRESSION_VIEW);
if (part == null) {
try {
page.showView(IDebugUIConstants.ID_EXPRESSION_VIEW);
}
catch (PartInitException e) {
reportError(e.getStatus().getMessage());
}
} else {
page.bringToTop(part);
}
}
}
private void createWatchExpression(String expr) {
IWatchExpression expression= DebugPlugin.getDefault().getExpressionManager().newWatchExpression(expr);
DebugPlugin.getDefault().getExpressionManager().addExpression(expression);
IAdaptable object = DebugUITools.getDebugContext();
IDebugElement context= null;
if (object instanceof IDebugElement) {
context = (IDebugElement) object;
}
else if (object instanceof ILaunch) {
context = ((ILaunch) object).getDebugTarget();
}
expression.setExpressionContext(context);
}
private static IWorkbenchWindow getActiveWorkbenchWindow() {
return PlatformUI.getWorkbench().getActiveWorkbenchWindow();
}
private static IWorkbenchPage getActivePage() {
IWorkbenchWindow w = getActiveWorkbenchWindow();
if (w != null) {
return w.getActivePage();
}
return null;
}
private void reportError(String message) {
throw new RuntimeException(message);
}
/**
* Disposes this action's debug model presentation, if
* one was created.
*/
private void disposeDebugModelPresentation() {
if (fPresentation != null) {
fPresentation.dispose();
}
}
private void setWindow(IWorkbenchWindow window) {
fWindow = window;
}
private void setNewTargetPart(IWorkbenchPart newTargetPart) {
fNewTargetPart = newTargetPart;
}
private void setTargetPart(IWorkbenchPart part) {
fTargetPart= part;
}
private void setSelectedObject(Object selection) {
fSelection = selection;
}
private IWorkbenchPart getTargetPart() {
return fTargetPart;
}
private void setAction(IAction action) {
fAction = action;
}
private ISelection getTargetSelection() {
IWorkbenchPart part = getTargetPart();
if (part != null) {
ISelectionProvider provider = part.getSite().getSelectionProvider();
if (provider != null) {
return provider.getSelection();
}
}
return null;
}
private boolean textHasContent(String text) {
if (text != null) {
int length= text.length();
if (length > 0) {
for (int i= 0; i < length; i++) {
if (Character.isLetterOrDigit(text.charAt(i))) {
return true;
}
}
}
}
return false;
}
private Object resolveSelectedObjectUsingToken(Object selectedObject, ITextSelection ts, IEditorPart editor) {
ITextEditor textEditor= (ITextEditor) editor;
IDocument doc= textEditor.getDocumentProvider().getDocument(editor.getEditorInput());
fRegion= JavaWordFinder.findWord(doc, ts.getOffset());
if (fRegion != null) {
try {
selectedObject= doc.get(fRegion.getOffset(), fRegion.getLength());
}
catch (BadLocationException e) {
}
}
return selectedObject;
}
/**
* Resolves the selected object in the target part, or <code>null</code>
* if there is no selection.
*/
private void resolveSelectedObject() {
Object selectedObject= null;
fRegion = null;
ISelection selection= getTargetSelection();
if (selection instanceof ITextSelection) {
ITextSelection ts = (ITextSelection)selection;
String text= ts.getText();
if (textHasContent(text)) {
selectedObject= text;
fRegion = new Region(ts.getOffset(), ts.getLength());
}
else if (getTargetPart() instanceof IEditorPart) {
IEditorPart editor= (IEditorPart) getTargetPart();
if (editor instanceof ITextEditor) {
selectedObject = resolveSelectedObjectUsingToken(selectedObject, ts, editor);
}
}
}
else if (selection instanceof IStructuredSelection) {
if (!selection.isEmpty()) {
if (getTargetPart().getSite().getId().equals(IDebugUIConstants.ID_DEBUG_VIEW)) {
//work on the editor selection
IEditorPart editor= getTargetPart().getSite().getPage().getActiveEditor();
setTargetPart(editor);
selection= getTargetSelection();
if (selection instanceof ITextSelection) {
ITextSelection ts = (ITextSelection)selection;
String text= ts.getText();
if (textHasContent(text)) {
selectedObject= text;
}
else if (editor instanceof ITextEditor) {
selectedObject = resolveSelectedObjectUsingToken(selectedObject, ts, editor);
}
}
} else {
IStructuredSelection ss= (IStructuredSelection)selection;
Iterator<?> elements = ss.iterator();
while (elements.hasNext()) {
if (!(elements.next() instanceof QVTOVariable)) {
setSelectedObject(null);
return;
}
}
selectedObject= ss;
}
}
}
setSelectedObject(selectedObject);
}
/**
* Updates the enabled state of the action that this is a
* delegate for.
*/
private void update() {
if (fAction != null) {
resolveSelectedObject();
}
}
public void dispose() {
disposeDebugModelPresentation();
IWorkbenchWindow win = fWindow;
if (win != null) {
win.getPartService().removePartListener(this);
}
}
public void init(IWorkbenchWindow window) {
setWindow(window);
IWorkbenchPage page= window.getActivePage();
if (page != null) {
setTargetPart(page.getActivePart());
}
window.getPartService().addPartListener(this);
update();
}
public void run(IAction action) {
update();
run();
}
public void selectionChanged(IAction action, ISelection selection) {
setAction(action);
}
/**
* @see IPartListener#partActivated(IWorkbenchPart)
*/
public void partActivated(IWorkbenchPart part) {
setTargetPart(part);
}
/**
* @see IPartListener#partBroughtToTop(IWorkbenchPart)
*/
public void partBroughtToTop(IWorkbenchPart part) {
}
/**
* @see IPartListener#partClosed(IWorkbenchPart)
*/
public void partClosed(IWorkbenchPart part) {
if (part == getTargetPart()) {
setTargetPart(null);
}
if (part == fNewTargetPart) {
setNewTargetPart(null);
}
}
/**
* @see IPartListener#partDeactivated(IWorkbenchPart)
*/
public void partDeactivated(IWorkbenchPart part) {
}
/**
* @see IPartListener#partOpened(IWorkbenchPart)
*/
public void partOpened(IWorkbenchPart part) {
}
public void setActiveEditor(IAction action, IEditorPart targetEditor) {
setAction(action);
setTargetPart(targetEditor);
}
private static class JavaWordFinder {
public static IRegion findWord(IDocument document, int offset) {
int start= -1;
int end= -1;
try {
int pos= offset;
char c;
while (pos >= 0) {
c= document.getChar(pos);
if (!Character.isJavaIdentifierPart(c)) {
break;
}
--pos;
}
start= pos;
pos= offset;
int length= document.getLength();
while (pos < length) {
c= document.getChar(pos);
if (!Character.isJavaIdentifierPart(c)) {
break;
}
++pos;
}
end= pos;
}
catch (BadLocationException x) {
}
if (start > -1 && end > -1) {
if (start == offset && end == offset) {
return new Region(offset, 0);
}
else if (start == offset) {
return new Region(start, end - start);
}
else {
return new Region(start + 1, end - start - 1);
}
}
return null;
}
}
}