1 19 20 package org.netbeans.lib.editor.codetemplates; 21 22 import java.util.ArrayList ; 23 import java.util.Collection ; 24 import java.util.Collections ; 25 import java.util.LinkedHashMap ; 26 import java.util.Iterator ; 27 import java.util.Map ; 28 import javax.swing.text.Position ; 29 import org.netbeans.lib.editor.codetemplates.spi.CodeTemplateInsertRequest; 30 import org.netbeans.lib.editor.codetemplates.spi.CodeTemplateParameter; 31 import org.netbeans.lib.editor.util.swing.MutablePositionRegion; 32 33 38 public final class CodeTemplateParameterImpl { 39 40 private static final String NULL_PARAMETER_NAME = "<null>"; 42 private static final String NULL_HINT_NAME = "<null>"; 44 private static final String TRUE_HINT_VALUE = "true"; 46 49 public static CodeTemplateParameterImpl get(CodeTemplateParameter parameter) { 50 return CodeTemplateSpiPackageAccessor.get().getImpl(parameter); 51 } 52 53 56 private final CodeTemplateInsertHandler handler; 57 58 private final CodeTemplateParameter parameter; 59 60 private String value; 61 62 private int parametrizedTextStartOffset; 63 64 private int parametrizedTextEndOffset; 65 66 private CodeTemplateParameter master; 67 68 private Collection slaves; 69 70 private Collection slavesUnmodifiable; 71 72 private String name; 73 74 private Map hints; 75 76 private Map hintsUnmodifiable; 77 78 private SyncDocumentRegion region; 79 80 private MutablePositionRegion positionRegion; 81 82 private boolean editable; 83 84 private boolean userModified; 85 86 87 CodeTemplateParameterImpl(CodeTemplateInsertHandler handler, 88 String parametrizedText, int parametrizedTextOffset) { 89 this.handler = handler; this.parametrizedTextStartOffset = parametrizedTextOffset; 91 92 CodeTemplateInsertRequest.class.getName(); 94 95 this.parameter = CodeTemplateSpiPackageAccessor.get().createParameter(this); 96 parseParameterContent(parametrizedText); 97 } 98 99 public CodeTemplateParameter getParameter() { 100 return parameter; 101 } 102 103 public CodeTemplateInsertHandler getHandler() { 104 return handler; 105 } 106 107 110 public String getName() { 111 return name; 112 } 113 114 public String getValue() { 115 return isSlave() ? master.getValue() 116 : ((handler != null && handler.isInserted()) ? handler.getDocParameterValue(this) : value); 117 } 118 119 public void setValue(String newValue, boolean fromAPI) { 120 if (isSlave()) { 121 throw new IllegalStateException ("Cannot set value for slave parameter"); } 123 if (newValue == null) { 124 throw new NullPointerException ("newValue cannot be null"); } 126 if (!newValue.equals(value)) { 127 if (fromAPI) { 128 if (!handler.isReleased()) { 129 if (handler.isInserted()) { handler.setDocParameterValue(this, newValue); 131 } else { this.value = newValue; 133 } 134 } 135 136 } else { this.value = newValue; 138 } 139 140 handler.resetCachedInsertText(); 141 } 142 } 143 144 public boolean isEditable() { 145 return editable; 146 } 147 148 public boolean isUserModified() { 149 return userModified; 150 } 151 152 void markUserModified() { 153 this.userModified = true; 154 } 155 156 159 public int getParametrizedTextStartOffset() { 160 return parametrizedTextStartOffset; 161 } 162 163 170 public int getParametrizedTextEndOffset() { 171 return parametrizedTextEndOffset; 172 } 173 174 public int getInsertTextOffset() { 175 if (handler != null) { 176 if (!handler.isInserted()) { 177 handler.checkInsertTextBuilt(); 178 } 179 return (positionRegion != null) 180 ? positionRegion.getStartOffset() - handler.getInsertOffset() 181 : 0; 182 } else { return (positionRegion != null) ? positionRegion.getStartOffset() : 0; 184 } 185 } 186 187 void resetPositions(Position startPosition, Position endPosition) { 188 if (positionRegion == null) { 189 positionRegion = new MutablePositionRegion(startPosition, endPosition); 190 } else { 191 positionRegion.reset(startPosition, endPosition); 192 } 193 } 194 195 public MutablePositionRegion getPositionRegion() { 196 return positionRegion; 197 } 198 199 public Map getHints() { 200 return (hintsUnmodifiable != null) ? hintsUnmodifiable : Collections.EMPTY_MAP; 201 } 202 203 public CodeTemplateParameter getMaster() { 204 return master; 205 } 206 207 public Collection getSlaves() { 208 return (slaves != null) ? slaves : Collections.EMPTY_LIST; 209 } 210 211 public boolean isSlave() { 212 return (master != null); 213 } 214 215 SyncDocumentRegion getRegion() { 216 return region; 217 } 218 219 void setRegion(SyncDocumentRegion region) { 220 this.region = region; 221 } 222 223 226 void markSlave(CodeTemplateParameter master) { 227 CodeTemplateParameterImpl masterImpl = paramImpl(master); 228 if (getMaster() != null) { 229 throw new IllegalStateException (toString() + " already slave of " + master); } 231 setMaster(master); 232 masterImpl.addSlave(getParameter()); 233 234 if (slaves != null) { 236 for (Iterator it = slaves.iterator(); it.hasNext();) { 237 CodeTemplateParameterImpl paramImpl = paramImpl((CodeTemplateParameter)it.next()); 238 paramImpl.setMaster(master); 239 masterImpl.addSlave(paramImpl.getParameter()); 240 } 241 slaves.clear(); 242 } 243 } 244 245 private static CodeTemplateParameterImpl paramImpl(CodeTemplateParameter param) { 246 return CodeTemplateSpiPackageAccessor.get().getImpl(param); 247 } 248 249 258 private void parseParameterContent(String parametrizedText) { 259 int index = parametrizedTextStartOffset + 2; 260 String hintName = null; 261 String hintValue = null; 262 boolean afterEquals = false; 263 int nameStartIndex = -1; 264 boolean insideStringLiteral = false; 265 StringBuffer stringLiteralText = new StringBuffer (); 266 267 while (true) { 268 String completedString = null; 270 if (index >= parametrizedText.length()) { 271 break; 272 } 273 char ch = parametrizedText.charAt(index); 274 275 if (insideStringLiteral) { if (ch == '"') { insideStringLiteral = false; 278 completedString = stringLiteralText.toString(); 279 stringLiteralText.setLength(0); 281 } else if (ch == '\\') { 282 index = escapedChar(parametrizedText, 283 index + 1, stringLiteralText); 284 } else { stringLiteralText.append(ch); 286 } 287 288 } else { if (Character.isWhitespace(ch) || ch == '=' || ch == '}') { 290 if (nameStartIndex != -1) { completedString = parametrizedText.substring( 292 nameStartIndex, index); 293 nameStartIndex = -1; 294 } else { 295 } 297 298 } else if (ch == '"') { insideStringLiteral = true; 300 301 } else { if (nameStartIndex == -1) { 303 nameStartIndex = index; 304 } 305 } 306 } 307 308 if (completedString != null) { 309 if (name == null) { name = completedString; 311 } else { if (hints == null) { hints = new LinkedHashMap (4); 314 hintsUnmodifiable = Collections.unmodifiableMap(hints); 315 } 316 317 if (hintName == null) { if (afterEquals) { hints.put(NULL_HINT_NAME, completedString); 321 afterEquals = false; 322 324 } else { hintName = completedString; 326 } 327 328 } else { if (afterEquals) { hints.put(hintName, completedString); 331 afterEquals = false; 332 hintName = null; 333 334 } else { hints.put(hintName, TRUE_HINT_VALUE); 336 hintName = completedString; 337 } 338 } 339 } 340 } 341 342 if (!insideStringLiteral) { 343 if (ch == '=') { 344 afterEquals = true; 345 } else if (ch == '}') { if (hintName != null) { hints.put(hintName, TRUE_HINT_VALUE); 348 hintName = null; 349 } 350 break; 351 } 352 } 353 354 index++; } 356 357 if (name == null) { 358 name = NULL_PARAMETER_NAME; 359 } 360 361 String defaultValue = (String )getHints().get(CodeTemplateParameter.DEFAULT_VALUE_HINT_NAME); 363 if (defaultValue == null) { defaultValue = name; 365 } 366 value = defaultValue; 367 368 if (name.equals(CodeTemplateParameter.CURSOR_PARAMETER_NAME)) { 369 editable = false; 370 value = ""; 371 } else if (name.equals(CodeTemplateParameter.SELECTION_PARAMETER_NAME)) { 372 editable = false; 373 if (handler != null) { 374 value = handler.getComponent().getSelectedText(); 375 if (value == null) 376 value = ""; else if (getHints().get(CodeTemplateParameter.LINE_HINT_NAME) != null && !value.endsWith("\n")) value += "\n"; } 380 } else { 381 editable = !isHintValueFalse(CodeTemplateParameter.EDITABLE_HINT_NAME); 382 } 383 384 parametrizedTextEndOffset = index + 1; 385 } 386 387 private boolean isHintValueFalse(String hintName) { 388 String hintValue = (String )getHints().get(hintName); 389 return (hintValue != null) && "false".equals(hintValue.toLowerCase()); } 391 392 403 private int escapedChar(CharSequence text, int index, StringBuffer output) { 404 if (index == text.length()) { 405 output.append('\\'); 406 } else { 407 switch (text.charAt(index++)) { 408 case '\\': 409 output.append('\\'); 410 break; 411 case 'n': 412 output.append('\n'); 413 break; 414 case 'r': 415 output.append('\r'); 416 break; 417 case '"': 418 output.append('"'); 419 break; 420 case '\'': 421 output.append('\''); 422 break; 423 424 case 'u': int value = 0; 426 for (int i = 0; i < 4; i++) { 427 if (index < text.length()) { 428 char ch = text.charAt(index); 429 if (ch >= '0' && ch <= '9') { 430 value = (value << 4) + (ch - '0'); 431 } else if (ch >= 'a' && ch <= 'f') { 432 value = (value << 4) + 10 + (ch - 'a'); 433 } else if (ch >= 'A' && ch <= 'F') { 434 value = (value << 4) + 10 + (ch - 'F'); 435 } else { break; 437 } 438 } 439 index++; 440 } 441 output.append(value); 442 break; 443 444 default: index--; 446 output.append('\\'); 447 break; 448 } 449 } 450 451 return index; } 453 454 private void addSlave(CodeTemplateParameter slave) { 455 if (slaves == null) { 456 slaves = new ArrayList (2); 457 slavesUnmodifiable = Collections.unmodifiableCollection(slaves); 458 } 459 slaves.add(slave); 460 } 461 462 private void setMaster(CodeTemplateParameter master) { 463 this.master = master; 464 } 465 466 public String toString() { 467 return "name=" + getName() + ", slave=" + isSlave() + ", value=" + getValue(); } 470 471 } 472 | Popular Tags |