blob: f6874b8eae9498bfdc81fe2b8782f198cd197e05 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2006 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
*
* Contributors:
* IBM Corporation - initial implementation
*******************************************************************************/
package org.eclipse.jdt.internal.debug.ui.actions;
import com.ibm.icu.text.MessageFormat;
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.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.TextViewerUndoManager;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
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 Label fEvaluateLabel;
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
*/
protected ExpressionInputDialog(Shell parentShell, IJavaVariable variable) {
super(parentShell);
setShellStyle(SWT.CLOSE|SWT.MIN|SWT.MAX|SWT.RESIZE);
fVariable= variable;
}
/**
* Creates and populates the dialog area
*/
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
createInputArea(composite);
// Create the error reporting text area
createErrorText(composite);
// Create the source viewer after creating the error text so that any
// necessary error messages can be set.
populateInputArea();
return composite;
}
/**
* Creates the text widget for reporting errors
*/
protected void createErrorText(Composite parent) {
fErrorText= new Text(parent, SWT.READ_ONLY);
fErrorText.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
| GridData.HORIZONTAL_ALIGN_FILL));
fErrorText.setBackground(fErrorText.getDisplay()
.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
fErrorText.setFont(parent.getFont());
}
/**
* Creates the composite that will be used to contain the
* input widgetry.
* @param composite the parent composite
*/
protected void createInputArea(Composite parent) {
fInputArea= new Composite(parent, SWT.NONE);
GridData gridData = new GridData(GridData.FILL_BOTH);
fInputArea.setLayoutData(gridData);
GridLayout layout = new GridLayout();
layout.marginHeight= 0;
layout.marginWidth= 0;
fInputArea.setLayout(layout);
Dialog.applyDialogFont(fInputArea);
}
/**
* Creates the appropriate widgetry in the input area. This
* method is intended to be overridden by subclasses who wish
* to use alternate input widgets.
*/
protected void populateInputArea() {
createSourceViewer();
}
/**
* Creates the source viewer that allows the user to enter
* an evaluation expression.
*/
protected void createSourceViewer() {
Composite parent= fInputArea;
String name= ActionMessages.ExpressionInputDialog_3;
try {
name= fVariable.getName();
} catch (DebugException e) {
JDIDebugUIPlugin.log(e);
}
fEvaluateLabel= new Label(parent, SWT.WRAP);
fEvaluateLabel.setText(MessageFormat.format(ActionMessages.ExpressionInputDialog_0, new String[] {name}));
GridData data = new GridData(GridData.FILL_HORIZONTAL);
data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);
fEvaluateLabel.setLayoutData(data);
fEvaluateLabel.setFont(parent.getFont());
fSourceViewer= new JDISourceViewer(parent, null, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
fSourceViewer.setInput(parent);
configureSourceViewer();
fSourceViewer.doOperation(ITextOperationTarget.SELECT_ALL);
}
/**
* 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() {
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() {
public void documentAboutToBeChanged(DocumentEvent event) {
}
public void documentChanged(DocumentEvent event) {
refreshValidState();
}
};
fSourceViewer.getDocument().addDocumentListener(fDocumentListener);
IHandler handler = new AbstractHandler() {
public Object execute(ExecutionEvent event) throws org.eclipse.core.commands.ExecutionException {
fSourceViewer.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS);
return null;
}
};
IWorkbench workbench = PlatformUI.getWorkbench();
fService = (IHandlerService)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();
StringBuffer buffer= new StringBuffer(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() {
String errorMessage= null;
String text= fSourceViewer.getDocument().get();
boolean valid= text != null && text.trim().length() > 0;
if (!valid) {
errorMessage= ActionMessages.ExpressionInputDialog_1;
}
setErrorMessage(errorMessage);
}
/**
* 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.
*/
protected void okPressed() {
fResult= getText();
dispose();
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();
}
/**
* Disposes the source viewer. This method is intended to be overridden
* by subclasses.
*/
protected void dispose() {
disposeSourceViewer();
}
/**
* Disposes the source viewer and all associated widgetry.
*/
protected void disposeSourceViewer() {
if(fActivation != null) {
fService.deactivateHandler(fActivation);
}
if (fSourceViewer != null) {
fSourceViewer.getDocument().removeDocumentListener(fDocumentListener);
fSourceViewer.getTextWidget().dispose();
fSourceViewer.dispose();
fSourceViewer= null;
}
if (fEvaluateLabel != null) {
fEvaluateLabel.dispose();
fEvaluateLabel= null;
}
fDocumentListener= null;
fCompletionProcessor= null;
}
/**
* 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.
*/
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.
*/
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()
*/
public boolean close() {
dispose();
return super.close();
}
/* (non-Javadoc)
* @see org.eclipse.jface.dialogs.Dialog#getDialogBoundsSettings()
*/
protected IDialogSettings getDialogBoundsSettings() {
IDialogSettings settings = JDIDebugUIPlugin.getDefault().getDialogSettings();
IDialogSettings section = settings.getSection(getDialogSettingsSectionName());
if (section == null) {
section = settings.addNewSection(getDialogSettingsSectionName());
}
return section;
}
protected String getDialogSettingsSectionName() {
return "EXPRESSION_INPUT_DIALOG"; //$NON-NLS-1$
}
}