| /******************************************************************************* |
| * Copyright (c) 2004, 2015 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.debug.ui.actions; |
| |
| import org.eclipse.core.commands.AbstractHandler; |
| import org.eclipse.core.commands.ExecutionEvent; |
| import org.eclipse.core.commands.IHandler; |
| import org.eclipse.debug.core.DebugException; |
| import org.eclipse.debug.core.model.IValue; |
| import org.eclipse.debug.internal.ui.SWTFactory; |
| import org.eclipse.jdt.debug.core.IJavaVariable; |
| import org.eclipse.jdt.internal.debug.core.model.JDINullValue; |
| import org.eclipse.jdt.internal.debug.ui.IJavaDebugHelpContextIds; |
| import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin; |
| import org.eclipse.jdt.internal.debug.ui.JDISourceViewer; |
| import org.eclipse.jdt.internal.debug.ui.contentassist.CurrentFrameContext; |
| import org.eclipse.jdt.internal.debug.ui.contentassist.JavaDebugContentAssistProcessor; |
| import org.eclipse.jdt.internal.debug.ui.display.DisplayViewerConfiguration; |
| import org.eclipse.jdt.ui.text.IJavaPartitions; |
| import org.eclipse.jdt.ui.text.JavaTextTools; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.dialogs.IDialogSettings; |
| import org.eclipse.jface.dialogs.TrayDialog; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.DocumentEvent; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.IDocumentListener; |
| import org.eclipse.jface.text.ITextOperationTarget; |
| import org.eclipse.jface.text.IUndoManager; |
| import org.eclipse.jface.text.TextViewer; |
| import org.eclipse.jface.text.TextViewerUndoManager; |
| import org.eclipse.jface.text.contentassist.IContentAssistProcessor; |
| import org.eclipse.jface.text.source.ISourceViewer; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Text; |
| import org.eclipse.ui.IWorkbench; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.handlers.IHandlerActivation; |
| import org.eclipse.ui.handlers.IHandlerService; |
| import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; |
| |
| /** |
| * A dialog which prompts the user to enter an expression for |
| * evaluation. |
| */ |
| public class ExpressionInputDialog extends TrayDialog { |
| |
| protected IJavaVariable fVariable; |
| protected String fResult= null; |
| |
| // Input area composite which acts as a placeholder for |
| // input widgetry that is created/disposed dynamically. |
| protected Composite fInputArea; |
| // Source viewer widgets |
| protected Composite fSourceViewerComposite; |
| protected JDISourceViewer fSourceViewer; |
| protected IContentAssistProcessor fCompletionProcessor; |
| protected IDocumentListener fDocumentListener; |
| protected IHandlerService fService; |
| protected IHandlerActivation fActivation; |
| // protected HandlerSubmission fSubmission; |
| // Text for error reporting |
| protected Text fErrorText; |
| |
| /** |
| * @param parentShell the shell to create the dialog in |
| * @param variable the variable being edited |
| */ |
| protected ExpressionInputDialog(Shell parentShell, IJavaVariable variable) { |
| super(parentShell); |
| setShellStyle(SWT.CLOSE|SWT.MIN|SWT.MAX|SWT.RESIZE); |
| fVariable= variable; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite) |
| */ |
| @Override |
| protected Control createDialogArea(Composite parent) { |
| IWorkbench workbench = PlatformUI.getWorkbench(); |
| workbench.getHelpSystem().setHelp( |
| parent, |
| IJavaDebugHelpContextIds.EXPRESSION_INPUT_DIALOG); |
| |
| Composite composite= (Composite) super.createDialogArea(parent); |
| |
| // Create the composite which will hold the input widgetry |
| fInputArea = createInputArea(composite); |
| // Create the error reporting text area |
| fErrorText = createErrorText(composite); |
| // Create the source viewer after creating the error text so that any |
| // necessary error messages can be set. |
| populateInputArea(fInputArea); |
| return composite; |
| } |
| |
| /** |
| * Returns the text widget for reporting errors |
| * @param parent parent composite |
| * @return the error text widget |
| */ |
| protected Text createErrorText(Composite parent) { |
| Text text = SWTFactory.createText(parent, SWT.READ_ONLY, 1, ""); //$NON-NLS-1$ |
| text.setBackground(text.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); |
| return text; |
| } |
| |
| /** |
| * Returns the composite that will be used to contain the |
| * input widgetry. |
| * @param composite the parent composite |
| * @return the composite that will contain the input widgets |
| */ |
| protected Composite createInputArea(Composite parent) { |
| Composite composite = SWTFactory.createComposite(parent, parent.getFont(), 1, 1, GridData.FILL_BOTH, 0, 0); |
| Dialog.applyDialogFont(composite); |
| return composite; |
| } |
| |
| /** |
| * Creates the appropriate widgetry in the input area. This |
| * method is intended to be overridden by subclasses who wish |
| * to use alternate input widgets. |
| * @param parent parent composite |
| */ |
| protected void populateInputArea(Composite parent) { |
| fSourceViewerComposite = SWTFactory.createComposite(parent, parent.getFont(), 1, 1, GridData.FILL_BOTH, 0, 0); |
| |
| String name= ActionMessages.ExpressionInputDialog_3; |
| try { |
| name= fVariable.getName(); |
| } catch (DebugException e) { |
| JDIDebugUIPlugin.log(e); |
| } |
| |
| SWTFactory.createWrapLabel(fSourceViewerComposite, NLS.bind(ActionMessages.ExpressionInputDialog_0, new String[] {name}), 1, convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH)); |
| |
| fSourceViewer= new JDISourceViewer(fSourceViewerComposite, null, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); |
| fSourceViewer.setInput(fSourceViewerComposite); |
| configureSourceViewer(); |
| fSourceViewer.doOperation(ITextOperationTarget.SELECT_ALL); |
| } |
| |
| /** |
| * Sets the visibility of the source viewer and the exclude attribute of its layout. |
| * @param value If <code>true</code>, the viewer will be visible, if <code>false</code>, the viewer will be hidden. |
| */ |
| protected void setSourceViewerVisible(boolean value) { |
| if (fSourceViewerComposite != null){ |
| fSourceViewerComposite.setVisible(value); |
| GridData data = (GridData)fSourceViewerComposite.getLayoutData(); |
| data.exclude = !value; |
| if (value){ |
| fSourceViewer.getDocument().addDocumentListener(fDocumentListener); |
| activateHandler(); |
| } else if (fActivation != null) { |
| fSourceViewer.getDocument().removeDocumentListener(fDocumentListener); |
| fService.deactivateHandler(fActivation); |
| } |
| } |
| } |
| |
| /** |
| * Initializes the source viewer. This method is based on code in BreakpointConditionEditor. |
| */ |
| private void configureSourceViewer() { |
| JavaTextTools tools= JDIDebugUIPlugin.getDefault().getJavaTextTools(); |
| IDocument document= new Document(); |
| tools.setupJavaDocumentPartitioner(document, IJavaPartitions.JAVA_PARTITIONING); |
| fSourceViewer.configure(new DisplayViewerConfiguration() { |
| @Override |
| public IContentAssistProcessor getContentAssistantProcessor() { |
| return getCompletionProcessor(); |
| } |
| }); |
| fSourceViewer.setEditable(true); |
| fSourceViewer.setDocument(document); |
| final IUndoManager undoManager= new TextViewerUndoManager(10); |
| fSourceViewer.setUndoManager(undoManager); |
| undoManager.connect(fSourceViewer); |
| |
| fSourceViewer.getTextWidget().setFont(JFaceResources.getTextFont()); |
| |
| Control control= fSourceViewer.getControl(); |
| GridData gd = new GridData(GridData.FILL_BOTH); |
| control.setLayoutData(gd); |
| |
| gd= (GridData)fSourceViewer.getControl().getLayoutData(); |
| gd.heightHint= convertHeightInCharsToPixels(10); |
| gd.widthHint= convertWidthInCharsToPixels(40); |
| document.set(getInitialText(fVariable)); |
| |
| fDocumentListener= new IDocumentListener() { |
| @Override |
| public void documentAboutToBeChanged(DocumentEvent event) { |
| } |
| @Override |
| public void documentChanged(DocumentEvent event) { |
| refreshValidState(fSourceViewer); |
| } |
| }; |
| fSourceViewer.getDocument().addDocumentListener(fDocumentListener); |
| |
| activateHandler(); |
| } |
| |
| /** |
| * Activates the content assist handler. |
| */ |
| private void activateHandler(){ |
| IHandler handler = new AbstractHandler() { |
| @Override |
| public Object execute(ExecutionEvent event) throws org.eclipse.core.commands.ExecutionException { |
| fSourceViewer.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS); |
| return null; |
| } |
| }; |
| IWorkbench workbench = PlatformUI.getWorkbench(); |
| fService = workbench.getAdapter(IHandlerService.class); |
| fActivation = fService.activateHandler(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS, handler); |
| } |
| |
| /** |
| * Returns the text that should be shown in the source viewer upon |
| * initialization. The text should be presented in such a way that |
| * it can be used as an evaluation expression which will return the |
| * current value. |
| * @param variable the variable |
| * @return the initial text to display in the source viewer or <code>null</code> |
| * if none. |
| */ |
| protected String getInitialText(IJavaVariable variable) { |
| try { |
| String signature = variable.getSignature(); |
| if (signature.equals("Ljava/lang/String;")) { //$NON-NLS-1$ |
| IValue value = variable.getValue(); |
| if (!(value instanceof JDINullValue)) { |
| String currentValue= value.getValueString(); |
| StringBuilder buffer= new StringBuilder(currentValue.length()); |
| buffer.append('"'); // Surround value in quotes |
| char[] chars = currentValue.toCharArray(); |
| for (int i = 0; i < chars.length; i++) { |
| char c = chars[i]; |
| if (c == '\b') { |
| buffer.append("\\b"); //$NON-NLS-1$ |
| } else if (c == '\t') { |
| buffer.append("\\t"); //$NON-NLS-1$ |
| } else if (c == '\n') { |
| buffer.append("\\n"); //$NON-NLS-1$ |
| } else if (c == '\f') { |
| buffer.append("\\f"); //$NON-NLS-1$ |
| } else if (c == '\r') { |
| buffer.append("\\r"); //$NON-NLS-1$ |
| } else if (c == '"') { |
| buffer.append("\\\""); //$NON-NLS-1$ |
| } else if (c == '\'') { |
| buffer.append("\\\'"); //$NON-NLS-1$ |
| } else if (c == '\\') { |
| buffer.append("\\\\"); //$NON-NLS-1$ |
| } else { |
| buffer.append(c); |
| } |
| } |
| buffer.append('"'); // Surround value in quotes |
| return buffer.toString(); |
| } |
| } |
| } catch (DebugException e) { |
| } |
| return null; |
| } |
| |
| /** |
| * Return the completion processor associated with this viewer. |
| * @return DisplayConditionCompletionProcessor |
| */ |
| protected IContentAssistProcessor getCompletionProcessor() { |
| if (fCompletionProcessor == null) { |
| fCompletionProcessor= new JavaDebugContentAssistProcessor(new CurrentFrameContext()); |
| } |
| return fCompletionProcessor; |
| } |
| |
| /** |
| * @see org.eclipse.jface.preference.FieldEditor#refreshValidState() |
| */ |
| protected void refreshValidState(TextViewer viewer) { |
| String errorMessage= null; |
| if (viewer != null) { |
| String text= viewer.getDocument().get(); |
| boolean valid= text != null && text.trim().length() > 0; |
| if (!valid) { |
| errorMessage= ActionMessages.ExpressionInputDialog_1; |
| } |
| } |
| setErrorMessage(errorMessage); |
| } |
| |
| protected void refreshValidState() { |
| refreshValidState(fSourceViewer); |
| } |
| |
| /** |
| * Sets the error message to display to the user. <code>null</code> |
| * is the same as the empty string. |
| * @param message the error message to display to the user or |
| * <code>null</code> if the error message should be cleared |
| */ |
| protected void setErrorMessage(String message) { |
| if (message == null) { |
| message= ""; //$NON-NLS-1$ |
| } |
| fErrorText.setText(message); |
| getButton(IDialogConstants.OK_ID).setEnabled(message.length() == 0); |
| } |
| |
| /** |
| * Persist the dialog size and store the user's input on OK is pressed. |
| */ |
| @Override |
| protected void okPressed() { |
| fResult= getText(); |
| super.okPressed(); |
| } |
| |
| /** |
| * Returns the text that is currently displayed in the source viewer. |
| * @return the text that is currently displayed in the source viewer |
| */ |
| protected String getText() { |
| return fSourceViewer.getDocument().get(); |
| } |
| |
| /** |
| * Returns the text entered by the user or <code>null</code> if the user cancelled. |
| * |
| * @return the text entered by the user or <code>null</code> if the user cancelled |
| */ |
| public String getResult() { |
| return fResult; |
| } |
| |
| /** |
| * Initializes the dialog shell with a title. |
| */ |
| @Override |
| protected void configureShell(Shell newShell) { |
| super.configureShell(newShell); |
| newShell.setText(ActionMessages.ExpressionInputDialog_2); |
| } |
| |
| /** |
| * Override method to initialize the enablement of the OK button after |
| * it is created. |
| */ |
| @Override |
| protected void createButtonsForButtonBar(Composite parent) { |
| super.createButtonsForButtonBar(parent); |
| //do this here because setting the text will set enablement on the ok |
| // button |
| refreshValidState(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.window.Window#close() |
| */ |
| @Override |
| public boolean close() { |
| if (fActivation != null) { |
| fService.deactivateHandler(fActivation); |
| } |
| if (fSourceViewer != null) { |
| fSourceViewer.getDocument().removeDocumentListener(fDocumentListener); |
| fSourceViewer.dispose(); |
| fSourceViewer = null; |
| } |
| if (fSourceViewerComposite != null) { |
| fSourceViewerComposite.dispose(); |
| fSourceViewerComposite = null; |
| } |
| fDocumentListener = null; |
| fCompletionProcessor = null; |
| return super.close(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.dialogs.Dialog#getDialogBoundsSettings() |
| */ |
| @Override |
| protected IDialogSettings getDialogBoundsSettings() { |
| IDialogSettings settings = JDIDebugUIPlugin.getDefault().getDialogSettings(); |
| IDialogSettings section = settings.getSection(getDialogSettingsSectionName()); |
| if (section == null) { |
| section = settings.addNewSection(getDialogSettingsSectionName()); |
| } |
| return section; |
| } |
| |
| /** |
| * @return the name to use to save the dialog settings |
| */ |
| protected String getDialogSettingsSectionName() { |
| return "EXPRESSION_INPUT_DIALOG"; //$NON-NLS-1$ |
| } |
| } |