| /******************************************************************************* |
| * Copyright (c) 2000, 2018 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 |
| * |
| *******************************************************************************/ |
| package org.eclipse.dltk.internal.debug.ui.actions; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.Iterator; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.debug.ui.DebugUITools; |
| import org.eclipse.debug.ui.IDebugModelPresentation; |
| import org.eclipse.debug.ui.IDebugUIConstants; |
| import org.eclipse.dltk.debug.core.eval.IScriptEvaluationEngine; |
| import org.eclipse.dltk.debug.core.eval.IScriptEvaluationListener; |
| import org.eclipse.dltk.debug.core.eval.IScriptEvaluationResult; |
| import org.eclipse.dltk.debug.core.model.IScriptStackFrame; |
| import org.eclipse.dltk.debug.core.model.IScriptValue; |
| import org.eclipse.dltk.debug.core.model.IScriptVariable; |
| import org.eclipse.dltk.debug.ui.DLTKDebugUIPlugin; |
| import org.eclipse.dltk.internal.debug.ui.ScriptEvaluationContextManager; |
| import org.eclipse.dltk.internal.ui.editor.ScriptEditor; |
| import org.eclipse.dltk.internal.ui.text.ScriptWordFinder; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.dialogs.ErrorDialog; |
| import org.eclipse.jface.operation.IRunnableWithProgress; |
| 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.ITextViewer; |
| 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.osgi.util.NLS; |
| import org.eclipse.swt.custom.StyledText; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.ui.IEditorActionDelegate; |
| import org.eclipse.ui.IEditorPart; |
| import org.eclipse.ui.IObjectActionDelegate; |
| import org.eclipse.ui.IPartListener; |
| import org.eclipse.ui.IViewActionDelegate; |
| import org.eclipse.ui.IViewPart; |
| import org.eclipse.ui.IWorkbench; |
| 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.texteditor.ITextEditor; |
| |
| public class ScriptEvaluationAction implements IWorkbenchWindowActionDelegate, |
| IObjectActionDelegate, IPartListener, IScriptEvaluationListener, |
| IEditorActionDelegate, IViewActionDelegate { |
| |
| private static class ObjectResolver { |
| private IWorkbenchPart part; |
| private IRegion region; |
| |
| protected static ISelection getSelection(IWorkbenchPart part) { |
| if (part != null) { |
| ISelectionProvider provider = part.getSite() |
| .getSelectionProvider(); |
| if (provider != null) { |
| return provider.getSelection(); |
| } |
| } |
| |
| return null; |
| } |
| |
| protected static 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; |
| } |
| |
| protected Object resolveTextSelection(ITextSelection selection) { |
| String text = selection.getText(); |
| if (textHasContent(text)) { |
| region = new Region(selection.getOffset(), |
| selection.getLength()); |
| return text; |
| } else if (part instanceof IEditorPart) { |
| IEditorPart editor = (IEditorPart) part; |
| if (editor instanceof ITextEditor) { |
| ITextEditor textEditor = (ITextEditor) editor; |
| IDocument doc = textEditor.getDocumentProvider() |
| .getDocument(editor.getEditorInput()); |
| region = ScriptWordFinder.findWord(doc, |
| selection.getOffset()); |
| if (region != null) { |
| try { |
| return doc.get(region.getOffset(), |
| region.getLength()); |
| } catch (BadLocationException e) { |
| } |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| protected Object resolveStructuredSelection( |
| IStructuredSelection selection) { |
| if (!selection.isEmpty()) { |
| if (part.getSite().getId() |
| .equals(IDebugUIConstants.ID_DEBUG_VIEW)) { |
| IEditorPart editor = part.getSite().getPage() |
| .getActiveEditor(); |
| |
| ISelection newSelection = getSelection(editor); |
| if (newSelection instanceof ITextSelection) { |
| return resolveTextSelection( |
| (ITextSelection) newSelection); |
| } |
| } else { |
| Iterator<?> elements = selection.iterator(); |
| while (elements.hasNext()) { |
| Object element = elements.next(); |
| if (!(element instanceof IScriptVariable)) { |
| return null; |
| } |
| } |
| |
| return selection; |
| } |
| } |
| |
| return null; |
| } |
| |
| public ObjectResolver(IWorkbenchPart part) { |
| this.part = part; |
| } |
| |
| public Object resolveSelectedObject() { |
| ISelection selection = getSelection(part); |
| |
| if (selection instanceof ITextSelection) { |
| return resolveTextSelection((ITextSelection) selection); |
| } else if (selection instanceof IStructuredSelection) { |
| return resolveStructuredSelection( |
| (IStructuredSelection) selection); |
| } |
| |
| return null; |
| } |
| } |
| |
| private IWorkbenchWindow window; |
| private IWorkbenchPart part; |
| private IAction action; |
| private Object selectedObject; |
| private boolean evaluation; |
| |
| protected static IDebugModelPresentation getDebugModelPresentation( |
| String identifier) { |
| return DebugUITools.newDebugModelPresentation(identifier); |
| } |
| |
| private void setWindow(IWorkbenchWindow window) { |
| this.window = window; |
| } |
| |
| protected IWorkbenchWindow getWindow() { |
| return this.window; |
| } |
| |
| private void setPart(IWorkbenchPart part) { |
| this.part = part; |
| } |
| |
| protected IWorkbenchPart getPart() { |
| return this.editor != null ? this.editor : this.part; |
| } |
| |
| private void setAction(IAction action) { |
| this.action = action; |
| } |
| |
| protected IAction getAction() { |
| return action; |
| } |
| |
| private void setSelectedObject(Object object) { |
| this.selectedObject = object; |
| } |
| |
| protected Object getSelectedObject() { |
| return this.selectedObject; |
| } |
| |
| private void setEvaluating(boolean evaluation) { |
| this.evaluation = evaluation; |
| } |
| |
| protected boolean isEvaluating() { |
| return this.evaluation; |
| } |
| |
| protected void evaluationCleanup() { |
| setEvaluating(false); |
| // setTargetPart(fNewTargetPart); |
| } |
| |
| private ScriptEditor editor; |
| |
| private void setEditor(ScriptEditor editor) { |
| this.editor = editor; |
| } |
| |
| protected ScriptEditor getEditor() { |
| return this.editor; |
| } |
| |
| // IWorkbenchWindowActionDelegate |
| @Override |
| public void init(IWorkbenchWindow window) { |
| setWindow(window); |
| |
| IWorkbenchPage page = window.getActivePage(); |
| if (page != null) { |
| setPart(page.getActivePart()); |
| } |
| |
| window.getPartService().addPartListener(this); |
| update(); |
| } |
| |
| @Override |
| public void dispose() { |
| // disposeDebugModelPresentation(); |
| |
| IWorkbenchWindow window = getWindow(); |
| if (window != null) { |
| window.getPartService().removePartListener(this); |
| } |
| } |
| |
| // IObjectActionDelegate |
| @Override |
| public void setActivePart(IAction action, IWorkbenchPart targetPart) { |
| setAction(action); |
| setPart(targetPart); |
| update(); |
| } |
| |
| // IActionDelegate |
| @Override |
| public void run(IAction action) { |
| update(); |
| run(); |
| } |
| |
| @Override |
| public void selectionChanged(IAction action, ISelection selection) { |
| setAction(action); |
| } |
| |
| // IPartListener |
| @Override |
| public void partActivated(IWorkbenchPart part) { |
| setPart(part); |
| } |
| |
| @Override |
| public void partBroughtToTop(IWorkbenchPart part) { |
| |
| } |
| |
| @Override |
| public void partClosed(IWorkbenchPart part) { |
| if (part == getPart()) { |
| setPart(null); |
| } |
| } |
| |
| @Override |
| public void partDeactivated(IWorkbenchPart part) { |
| |
| } |
| |
| @Override |
| public void partOpened(IWorkbenchPart part) { |
| |
| } |
| |
| // Other stuff |
| protected void update() { |
| IAction action = getAction(); |
| if (action != null) { |
| ObjectResolver or = new ObjectResolver(getPart()); |
| setSelectedObject(or.resolveSelectedObject()); |
| } |
| } |
| |
| protected void showExpressionView() { |
| if (getPart().getSite().getId() |
| .equals(IDebugUIConstants.ID_EXPRESSION_VIEW)) { |
| return; |
| } |
| |
| IWorkbenchPage page = DLTKDebugUIPlugin.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); |
| } |
| } |
| } |
| |
| public static StyledText getStyledText(IWorkbenchPart part) { |
| ITextViewer viewer = part.getAdapter(ITextViewer.class); |
| StyledText textWidget = null; |
| if (viewer == null) { |
| Control control = part.getAdapter(Control.class); |
| if (control instanceof StyledText) { |
| textWidget = (StyledText) control; |
| } |
| } else { |
| textWidget = viewer.getTextWidget(); |
| } |
| return textWidget; |
| } |
| |
| public static Point getPopupAnchor(StyledText textWidget) { |
| if (textWidget != null) { |
| Point docRange = textWidget.getSelectionRange(); |
| int midOffset = docRange.x + (docRange.y / 2); |
| Point point = textWidget.getLocationAtOffset(midOffset); |
| point = textWidget.toDisplay(point); |
| |
| GC gc = new GC(textWidget); |
| gc.setFont(textWidget.getFont()); |
| int height = gc.getFontMetrics().getHeight(); |
| gc.dispose(); |
| point.y += height; |
| return point; |
| } |
| |
| return null; |
| } |
| |
| protected Shell getShell() { |
| if (getPart() != null) { |
| return getPart().getSite().getShell(); |
| } |
| |
| return DLTKDebugUIPlugin.getActiveWorkbenchShell(); |
| } |
| |
| protected IScriptStackFrame getStackFrameContext() { |
| IWorkbenchPart part = getPart(); |
| IScriptStackFrame frame = null; |
| if (part == null) { |
| frame = ScriptEvaluationContextManager |
| .getEvaluationContext(getWindow()); |
| } else { |
| frame = ScriptEvaluationContextManager.getEvaluationContext(part); |
| } |
| return frame; |
| } |
| |
| protected void run() { |
| final IScriptStackFrame stackFrame = getStackFrameContext(); |
| if (stackFrame == null) { |
| reportError(Messages.ScriptEvaluationAction_cannotGetStackFrame); |
| return; |
| } |
| |
| // setNewTargetPart(getTargetPart()); |
| |
| // Preparing runnable |
| IRunnableWithProgress runnable = monitor -> { |
| if (stackFrame.isSuspended()) { |
| Object selection = getSelectedObject(); |
| if (!(selection instanceof String)) { |
| return; |
| } |
| String expression = (String) selection; |
| |
| IScriptEvaluationEngine engine = stackFrame.getScriptThread() |
| .getEvaluationEngine(); |
| setEvaluating(true); |
| engine.asyncEvaluate(expression, stackFrame, |
| ScriptEvaluationAction.this); |
| } else { |
| throw new InvocationTargetException(null, |
| Messages.ScriptEvaluationAction_threadIsNotSuspended); |
| } |
| }; |
| |
| // Run |
| try { |
| IWorkbench workbench = DLTKDebugUIPlugin.getDefault() |
| .getWorkbench(); |
| workbench.getProgressService().busyCursorWhile(runnable); |
| } catch (InvocationTargetException e) { |
| evaluationCleanup(); |
| String message = e.getMessage(); |
| if (message == null) { |
| message = e.getClass().getName(); |
| if (e.getCause() != null) { |
| message = e.getCause().getClass().getName(); |
| if (e.getCause().getMessage() != null) { |
| message = e.getCause().getMessage(); |
| } |
| } |
| } |
| reportError(message); |
| } catch (InterruptedException e) { |
| } |
| } |
| |
| // Error reporting |
| public static String getExceptionMessage(Throwable exception) { |
| if (exception instanceof CoreException) { |
| CoreException ce = (CoreException) exception; |
| Throwable throwable = ce.getStatus().getException(); |
| if (throwable instanceof CoreException) { |
| // Traverse nested CoreExceptions |
| return getExceptionMessage(throwable); |
| } |
| return ce.getStatus().getMessage(); |
| } |
| String message = NLS.bind( |
| Messages.ScriptEvaluationAction_anExceptionOccurred, |
| exception.getClass()); |
| if (exception.getMessage() != null) { |
| message = NLS.bind( |
| Messages.ScriptEvaluationAction_anExceptionOccurred2, |
| message, exception.getMessage()); |
| } |
| return message; |
| } |
| |
| protected static String getErrorMessage(IScriptEvaluationResult result) { |
| String[] errors = result.getErrorMessages(); |
| if (errors.length == 0) { |
| return getExceptionMessage(result.getException()); |
| } |
| return getErrorMessage(errors); |
| } |
| |
| protected static String getErrorMessage(String[] errors) { |
| String message = ""; //$NON-NLS-1$ |
| for (int i = 0; i < errors.length; i++) { |
| String msg = errors[i]; |
| if (i == 0) { |
| message = msg; |
| } else { |
| message = NLS.bind(Messages.ScriptEvaluationAction_errorMessage, |
| message, msg); |
| } |
| } |
| return message; |
| } |
| |
| protected void reportErrors(IScriptEvaluationResult result) { |
| String message = getErrorMessage(result); |
| reportError(message); |
| } |
| |
| protected void reportError(String message) { |
| Status status = new Status(IStatus.ERROR, |
| DLTKDebugUIPlugin.getUniqueIdentifier(), IStatus.ERROR, message, |
| null); |
| ErrorDialog.openError(getShell(), |
| Messages.ScriptEvaluationAction_errorEvaluating, null, status); |
| } |
| |
| // IScriptEvaluationListener |
| @Override |
| public void evaluationComplete(IScriptEvaluationResult result) { |
| // if plug-in has shutdown, ignore - see bug# 8693 |
| if (DLTKDebugUIPlugin.getDefault() == null) { |
| return; |
| } |
| |
| final IScriptValue value = result.getValue(); |
| if (result.hasErrors() || value != null) { |
| final Display display = DLTKDebugUIPlugin.getStandardDisplay(); |
| if (display.isDisposed()) { |
| return; |
| } |
| |
| // Each action should implement this method for own purposes |
| displayResult(result); |
| } |
| |
| } |
| |
| protected void displayResult(IScriptEvaluationResult result) { |
| // Nothing by default |
| } |
| |
| // IEditorActionDelegate |
| @Override |
| public void setActiveEditor(IAction action, IEditorPart targetEditor) { |
| setEditor((ScriptEditor) targetEditor); |
| } |
| |
| // IViewActionDelegate |
| @Override |
| public void init(IViewPart view) { |
| setPart(view); |
| } |
| } |