| /******************************************************************************* |
| * 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(); |
| } |
| } |
| |
| } |