blob: c60eeeb601be17e686e3a5d4e21710ba0aa15c8b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2017 xored software, Inc. and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* xored software, Inc. - initial API and Implementation (Alex Panchenko)
*******************************************************************************/
package org.eclipse.dltk.debug.ui.display;
import org.eclipse.core.expressions.EvaluationResult;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.ExpressionInfo;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IDebugEventSetListener;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.dltk.console.ScriptConsoleConstants;
import org.eclipse.dltk.console.ui.ScriptConsole;
import org.eclipse.dltk.console.ui.internal.ScriptConsolePage;
import org.eclipse.dltk.debug.core.model.IScriptStackFrame;
import org.eclipse.dltk.debug.core.model.IScriptThread;
import org.eclipse.dltk.debug.ui.DLTKDebugUIPlugin;
import org.eclipse.dltk.internal.debug.ui.ScriptEvaluationContextManager;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.commands.ActionHandler;
import org.eclipse.jface.text.source.SourceViewerConfiguration;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.StyledTextDropTargetEffect;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISources;
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.console.IConsoleView;
import org.eclipse.ui.handlers.IHandlerActivation;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.part.IPageSite;
import org.eclipse.ui.texteditor.IUpdate;
public class DebugConsolePage extends ScriptConsolePage {
private DebugEventListener debugEventListener = null;
/**
* @param console
* @param view
* @param cfg
*/
public DebugConsolePage(ScriptConsole console, IConsoleView view,
SourceViewerConfiguration cfg) {
super(console, view, cfg);
}
@Override
protected IAction createTerminateConsoleAction() {
return null;
}
private IAction runAction;
private IAction resetOnLaunchAction;
private boolean resetOnLaunch;
private IHandlerActivation pasteHandler;
private IHandlerActivation copyHandler;
private IHandlerActivation cutHandler;
private IHandlerActivation selectAllHandler;
@Override
protected void createActions() {
super.createActions();
final IActionBars actionBars = getSite().getActionBars();
final IToolBarManager tbManager = actionBars.getToolBarManager();
tbManager.appendToGroup(ScriptConsoleConstants.SCRIPT_GROUP,
new OpenInputFieldAction(this));
runAction = new RunInputFieldAction(this);
tbManager.appendToGroup(ScriptConsoleConstants.SCRIPT_GROUP, runAction);
resetOnLaunchAction = new ResetOnLaunchAction(this);
resetOnLaunchAction.setChecked(resetOnLaunch);
actionBars.getMenuManager().add(resetOnLaunchAction);
updateActions();
}
private SashForm sash;
private StyledText inputField;
private boolean enabled = true;
/**
* @param value
*/
private void setEnabled(final boolean value) {
if (value != this.enabled) {
this.enabled = value;
if (inputField != null)
inputField.setEditable(value);
getViewer().setEditable(value);
final Control control = getViewer().getControl();
control.setBackground(value ? null
: control.getDisplay()
.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
}
}
@Override
public Control getControl() {
return sash != null ? sash : super.getControl();
}
/*
* @see TextConsolePage#createControl(Composite)
*/
@Override
public void createControl(Composite parent) {
sash = new SashForm(parent, SWT.VERTICAL | SWT.SMOOTH);
inputField = new StyledText(sash, SWT.V_SCROLL | SWT.H_SCROLL);
inputField.addFocusListener(new FocusListener() {
@Override
public void focusLost(FocusEvent e) {
if (pasteHandler != null) {
IHandlerService service = getSite()
.getService(IHandlerService.class);
service.deactivateHandler(pasteHandler);
service.deactivateHandler(copyHandler);
service.deactivateHandler(cutHandler);
service.deactivateHandler(selectAllHandler);
pasteHandler = null;
copyHandler = null;
cutHandler = null;
selectAllHandler = null;
}
}
@Override
public void focusGained(FocusEvent e) {
IHandlerService service = getSite()
.getService(IHandlerService.class);
Expression expression = new Expression() {
@Override
public final EvaluationResult evaluate(
final IEvaluationContext context) {
return EvaluationResult.TRUE;
}
@Override
public final void collectExpressionInfo(
final ExpressionInfo info) {
info.addVariableNameAccess(ISources.ACTIVE_EDITOR_NAME);
info.addVariableNameAccess(
ISources.ACTIVE_CURRENT_SELECTION_NAME);
}
};
pasteHandler = service.activateHandler(
IWorkbenchCommandConstants.EDIT_PASTE,
new ActionHandler(new PasteAction(inputField)),
expression);
copyHandler = service.activateHandler(
IWorkbenchCommandConstants.EDIT_COPY,
new ActionHandler(new CopyAction(inputField)),
expression);
cutHandler = service.activateHandler(
IWorkbenchCommandConstants.EDIT_CUT,
new ActionHandler(new CutAction(inputField)),
expression);
selectAllHandler = service.activateHandler(
IWorkbenchCommandConstants.EDIT_SELECT_ALL,
new ActionHandler(new SelectAllAction(inputField)),
expression);
}
});
DropTarget target = new DropTarget(inputField, DND.DROP_DEFAULT
| DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK);
target.setTransfer(new Transfer[] { TextTransfer.getInstance() });
target.addDropListener(new StyledTextDropTargetEffect(inputField) {
@Override
public void dragEnter(DropTargetEvent e) {
super.dragEnter(e);
if (e.detail == DND.DROP_DEFAULT)
e.detail = DND.DROP_COPY;
}
@Override
public void dragOperationChanged(DropTargetEvent e) {
super.dragOperationChanged(e);
if (e.detail == DND.DROP_DEFAULT)
e.detail = DND.DROP_COPY;
}
@Override
public void drop(DropTargetEvent e) {
super.drop(e);
Point selection = inputField.getSelectionRange();
inputField.replaceTextRange(selection.x, selection.y,
(String) e.data);
}
});
inputField.setEditable(true);
super.createControl(sash);
inputField.setFont(getViewer().getControl().getFont());
inputField.addModifyListener(e -> updateActions());
sash.setMaximizedControl(getViewer().getControl());
setEnabled(isDebuggerAvailable());
if (debugEventListener == null) {
debugEventListener = new DebugEventListener();
DebugPlugin.getDefault().addDebugEventListener(debugEventListener);
}
enableUpdateJob.schedule(500);
}
private boolean isDebuggerAvailable() {
final IPageSite site = getSite();
if (site == null) {
return false;
}
final IWorkbenchPage page = site.getPage();
if (page == null) {
return false;
}
final IWorkbenchPart part = page.getActivePart();
if (part == null) {
return false;
}
final IScriptStackFrame frame = ScriptEvaluationContextManager
.getEvaluationContext(part);
if (frame != null) {
final IScriptThread thread = frame.getScriptThread();
if (thread != null) {
return thread.isSuspended();
}
}
return false;
}
@Override
public void dispose() {
if (debugEventListener != null) {
DebugPlugin.getDefault()
.removeDebugEventListener(debugEventListener);
debugEventListener = null;
}
if (pasteHandler != null) {
IHandlerService service = getSite()
.getService(IHandlerService.class);
service.deactivateHandler(pasteHandler);
service.deactivateHandler(copyHandler);
service.deactivateHandler(cutHandler);
service.deactivateHandler(selectAllHandler);
}
super.dispose();
}
public boolean canExecuteInputField() {
return sash != null && sash.getMaximizedControl() == null
&& inputField.getText().length() != 0;
}
public void openInputField() {
if (sash != null) {
sash.setWeights(new int[] { 30, 70 });
sash.setMaximizedControl(null);
inputField.setFocus();
}
updateActions();
}
public void closeInputField() {
if (sash != null) {
final Control consoleControl = getViewer().getControl();
sash.setMaximizedControl(consoleControl);
consoleControl.setFocus();
}
updateActions();
}
private void updateActions() {
if (runAction instanceof IUpdate) {
((IUpdate) runAction).update();
}
}
public void executeInputField() {
if (inputField != null) {
final String input = inputField.getText();
((ScriptConsole) getConsole()).executeCommand(input);
}
}
private final Job enableUpdateJob = new Job("Enable update") { //$NON-NLS-1$
@Override
protected IStatus run(IProgressMonitor monitor) {
DLTKDebugUIPlugin.getStandardDisplay()
.asyncExec(() -> setEnabled(isDebuggerAvailable()));
return Status.OK_STATUS;
}
};
private final class DebugEventListener implements IDebugEventSetListener {
@Override
public void handleDebugEvents(DebugEvent[] events) {
enableUpdateJob.schedule(500);
if (resetOnLaunch && isTargetCreate(events)) {
DLTKDebugUIPlugin.getStandardDisplay().asyncExec(
() -> ((DebugConsole) getConsole()).clearConsole());
}
}
}
private static boolean isTargetCreate(DebugEvent[] events) {
for (int i = 0; i < events.length; ++i) {
final DebugEvent event = events[i];
if (event.getKind() == DebugEvent.CREATE
&& event.getSource() instanceof IDebugTarget) {
return true;
}
}
return false;
}
/**
* @return the resetOnLaunch
*/
public boolean isResetOnLaunch() {
return resetOnLaunch;
}
/**
* @param resetOnLaunch
* the resetOnLaunch to set
*/
public void setResetOnLaunch(boolean resetOnLaunch) {
this.resetOnLaunch = resetOnLaunch;
}
private static class PasteAction extends Action {
private StyledText text;
public PasteAction(StyledText text) {
this.text = text;
}
@Override
public void run() {
text.paste();
}
}
private static class CopyAction extends Action {
private StyledText text;
public CopyAction(StyledText text) {
this.text = text;
}
@Override
public void run() {
text.copy();
}
}
private static class CutAction extends Action {
private StyledText text;
public CutAction(StyledText text) {
this.text = text;
}
@Override
public void run() {
text.cut();
}
}
private static class SelectAllAction extends Action {
private StyledText text;
public SelectAllAction(StyledText text) {
this.text = text;
}
@Override
public void run() {
text.selectAll();
}
}
}