1 /******************************************************************************* 2 * Copyright (c) 2004, 2015 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial implementation 13 *******************************************************************************/ 14 package org.eclipse.jdt.internal.debug.ui.actions; 15 16 import org.eclipse.debug.core.DebugException; 17 import org.eclipse.debug.core.model.IVariable; 18 import org.eclipse.debug.ui.actions.IVariableValueEditor; 19 import org.eclipse.jdt.internal.debug.eval.ast.engine.ASTInstructionCompiler; 20 import org.eclipse.jdt.internal.debug.ui.IJavaDebugHelpContextIds; 21 import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin; 22 import org.eclipse.jface.dialogs.IInputValidator; 23 import org.eclipse.jface.dialogs.InputDialog; 24 import org.eclipse.jface.window.Window; 25 import org.eclipse.osgi.util.NLS; 26 import org.eclipse.swt.widgets.Composite; 27 import org.eclipse.swt.widgets.Control; 28 import org.eclipse.swt.widgets.Shell; 29 import org.eclipse.ui.IWorkbench; 30 import org.eclipse.ui.PlatformUI; 31 32 /** 33 * A variable value editor that prompts the user to set a primitive's value. 34 */ 35 public class JavaPrimitiveValueEditor implements IVariableValueEditor { 36 37 /** 38 * The signature of the edited variable. 39 */ 40 private String fSignature= null; 41 42 /** 43 * Creates a new editor for a variable with the given signature 44 * @param signature the signature of the primitive to be edited 45 */ JavaPrimitiveValueEditor(String signature)46 public JavaPrimitiveValueEditor(String signature) { 47 fSignature= signature; 48 } 49 50 /* (non-Javadoc) 51 * @see org.eclipse.debug.ui.actions.IVariableValueEditor#editVariable(org.eclipse.debug.core.model.IVariable, org.eclipse.swt.widgets.Shell) 52 */ 53 @Override editVariable(IVariable variable, Shell shell)54 public boolean editVariable(IVariable variable, Shell shell) { 55 try { 56 String name= variable.getName(); 57 String title= ActionMessages.JavaPrimitiveValueEditor_0; 58 String message= NLS.bind(ActionMessages.JavaPrimitiveValueEditor_1, new String[] {name}); 59 String initialValue= variable.getValue().getValueString(); 60 PrimitiveValidator validator= new PrimitiveValidator(); 61 InputDialog dialog= new InputDialog(shell, title, message, initialValue, validator){ 62 @Override 63 protected Control createDialogArea(Composite parent) { 64 IWorkbench workbench = PlatformUI.getWorkbench(); 65 workbench.getHelpSystem().setHelp(parent, IJavaDebugHelpContextIds.DEFAULT_INPUT_DIALOG); 66 return super.createDialogArea(parent); 67 } 68 }; 69 if (dialog.open() == Window.OK) { 70 String stringValue = dialog.getValue(); 71 stringValue = formatValue(stringValue); 72 if (stringValue.length() > 1 && stringValue.charAt(0) == '\\') { 73 // Compute value of octal of hexadecimal escape sequence 74 int i= validator.getEscapeValue(stringValue); 75 if (i != Integer.MAX_VALUE) { 76 stringValue= new String(new char[] { (char) i }); 77 } 78 } 79 variable.setValue(stringValue); 80 } 81 } catch (DebugException e) { 82 JDIDebugUIPlugin.errorDialog(shell, ActionMessages.JavaPrimitiveValueEditor_2, ActionMessages.JavaPrimitiveValueEditor_3, e); // 83 } 84 return true; 85 } 86 87 /* (non-Javadoc) 88 * @see org.eclipse.debug.ui.actions.IVariableValueEditor#saveVariable(org.eclipse.debug.core.model.IVariable, java.lang.String, org.eclipse.swt.widgets.Shell) 89 */ 90 @Override saveVariable(IVariable variable, String expression, Shell shell)91 public boolean saveVariable(IVariable variable, String expression, Shell shell) { 92 return false; 93 } 94 formatValue(String value)95 String formatValue(String value) { 96 try { 97 switch (fSignature.charAt(0)) { 98 case 'I': 99 return Integer.toString(ASTInstructionCompiler.parseIntValue(value)); 100 case 'J': 101 return Long.toString(ASTInstructionCompiler.parseLongValue(value)); 102 case 'S': 103 return Short.toString(ASTInstructionCompiler.parseShortValue(value)); 104 case 'F': 105 case 'D': 106 return ASTInstructionCompiler.removePrefixZerosAndUnderscores(value, false); 107 case 'B': 108 return Byte.toString(ASTInstructionCompiler.parseByteValue(value)); 109 } 110 } 111 catch(NumberFormatException nfe) {} 112 return value; 113 } 114 115 /** 116 * Input validator for primitive types 117 */ 118 protected class PrimitiveValidator implements IInputValidator { 119 /* (non-Javadoc) 120 * @see org.eclipse.jface.dialogs.IInputValidator#isValid(java.lang.String) 121 */ 122 @Override isValid(String newText)123 public String isValid(String newText) { 124 String type= null; 125 switch (fSignature.charAt(0)) { 126 case 'B': 127 try { 128 Byte.parseByte(newText); 129 } catch (NumberFormatException e) { 130 type= "byte"; //$NON-NLS-1$ 131 } 132 break; 133 case 'C': 134 if (newText.length() > 1 && newText.charAt(0) == '\\') { 135 // Possibly an escaped character 136 if (isSpecialCharacter(newText) || 137 isOctalEscape(newText) || 138 isUnicode(newText)) { 139 break; 140 } 141 } 142 if (newText.length() != 1) { 143 type="char"; //$NON-NLS-1$ 144 } 145 break; 146 case 'D': 147 try { 148 Double.parseDouble(ASTInstructionCompiler.removePrefixZerosAndUnderscores(newText, false)); 149 } catch (NumberFormatException e) { 150 type="double"; //$NON-NLS-1$ 151 } 152 break; 153 case 'F': 154 try { 155 Float.parseFloat(ASTInstructionCompiler.removePrefixZerosAndUnderscores(newText, false)); 156 } catch (NumberFormatException e) { 157 type="float"; //$NON-NLS-1$ 158 } 159 break; 160 case 'I': 161 try { 162 ASTInstructionCompiler.parseIntValue(newText); 163 } catch (NumberFormatException e) { 164 type="int"; //$NON-NLS-1$ 165 } 166 break; 167 case 'J': 168 try { 169 ASTInstructionCompiler.parseLongValue(newText); 170 } catch (NumberFormatException e) { 171 type="long"; //$NON-NLS-1$ 172 } 173 break; 174 case 'S': 175 try { 176 ASTInstructionCompiler.parseShortValue(newText); 177 } catch (NumberFormatException e) { 178 type="short"; //$NON-NLS-1$ 179 } 180 break; 181 case 'Z': 182 if (!("true".equals(newText) || "false".equals(newText))) { //$NON-NLS-1$ //$NON-NLS-2$ 183 type="boolean"; //$NON-NLS-1$ 184 } 185 break; 186 } 187 if (type != null) { 188 return NLS.bind(ActionMessages.JavaPrimitiveValueEditor_4, new String[] { type }); 189 } 190 return null; 191 } 192 isUnicode(String newText)193 private boolean isUnicode(String newText) { 194 if (newText.length() == 6) { 195 if (newText.charAt(1) == 'u') { 196 char[] chars = newText.toCharArray(); 197 for (int i = 2; i < chars.length; i++) { 198 if (!isHexDigit(chars[i])) { 199 return false; 200 } 201 } 202 return true; 203 } 204 } 205 return false; 206 } 207 isOctalEscape(String newText)208 private boolean isOctalEscape(String newText) { 209 char[] chars= newText.toCharArray(); 210 if (chars.length < 4) { 211 for (int i = 1; i < chars.length; i++) { 212 if (!isOctalDigit(chars[i])) { 213 return false; 214 } 215 } 216 return true; 217 } else if (chars.length == 4) { 218 char ch= chars[1]; 219 if (ch < '0' || ch > '3') { 220 return false; 221 } 222 for (int i = 2; i < chars.length; i++) { 223 if (!isOctalDigit(chars[i])) { 224 return false; 225 } 226 } 227 return true; 228 } 229 return false; 230 } 231 isSpecialCharacter(String newText)232 private boolean isSpecialCharacter(String newText) { 233 char ch= newText.charAt(1); 234 return newText.length() == 2 && 235 (ch == 'b' || 236 ch == 't' || 237 ch == 'n' || 238 ch == 'f' || 239 ch == 'r' || 240 ch == '"' || 241 ch == '\'' || 242 ch == '\\'); 243 } 244 245 isOctalDigit(char ch)246 private boolean isOctalDigit(char ch) { 247 return Character.digit(ch, 8) != -1; 248 } 249 isHexDigit(char ch)250 private boolean isHexDigit(char ch) { 251 return Character.digit(ch, 16) != -1; 252 } 253 254 /** 255 * Returns the integer value specified by the given string, which 256 * represents an octal or hexadecimal escape sequence. Returns 257 * Integer.MAX_VALUE if the given string is not a valid octal or 258 * hexadecimal escape sequence. 259 * 260 * @param string 261 * @return 262 */ getEscapeValue(String string)263 protected int getEscapeValue(String string) { 264 return ASTInstructionCompiler.parseIntValue(string); 265 } 266 } 267 268 } 269