1 11 package org.eclipse.jdt.internal.corext.refactoring.nls; 12 13 import java.util.ArrayList ; 14 import java.util.Iterator ; 15 import java.util.List ; 16 17 import org.eclipse.text.edits.DeleteEdit; 18 import org.eclipse.text.edits.InsertEdit; 19 import org.eclipse.text.edits.ReplaceEdit; 20 21 import org.eclipse.jface.text.BadLocationException; 22 import org.eclipse.jface.text.IDocument; 23 import org.eclipse.jface.text.TextUtilities; 24 25 public class PropertyFileDocumentModel { 26 27 private static final char[] HEX_DIGITS = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; 28 private List fKeyValuePairs; 29 private String fLineDelimiter; 30 31 public PropertyFileDocumentModel(IDocument document) { 32 parsePropertyDocument(document); 33 fLineDelimiter= TextUtilities.getDefaultLineDelimiter(document); 34 } 35 36 public int getIndex(String key) { 37 for (int i= 0; i < fKeyValuePairs.size(); i++) { 38 KeyValuePairModell keyValuePair = (KeyValuePairModell) fKeyValuePairs.get(i); 39 if (keyValuePair.getKey().equals(key)) { 40 return i; 41 } 42 } 43 return -1; 44 } 45 46 47 public InsertEdit insert(String key, String value) { 48 return insert(new KeyValuePair(key, value)); 49 } 50 51 public InsertEdit insert(KeyValuePair keyValuePair) { 52 KeyValuePairModell keyValuePairModell = new KeyValuePairModell(keyValuePair); 53 int index = findInsertPosition(keyValuePairModell); 54 KeyValuePairModell insertHere = (KeyValuePairModell) fKeyValuePairs.get(index); 55 int offset = insertHere.fOffset - insertHere.fLeadingWhiteSpaces; 56 57 String extra= ""; if (insertHere instanceof LastKeyValuePair && ((LastKeyValuePair)insertHere).needsNewLine()) { 59 extra= fLineDelimiter; 60 ((LastKeyValuePair)insertHere).resetNeedsNewLine(); 61 } 62 return new InsertEdit(offset, extra + keyValuePairModell.getEncodedText(fLineDelimiter)); 63 } 64 65 public InsertEdit[] insert(KeyValuePair[] keyValuePairs) { 66 InsertEdit[] inserts = new InsertEdit[keyValuePairs.length]; 67 for (int i = 0; i < keyValuePairs.length; i++) { 68 inserts[i] = insert(keyValuePairs[i]); 69 } 70 return inserts; 71 } 72 73 public DeleteEdit remove(String key) { 74 for (Iterator iter = fKeyValuePairs.iterator(); iter.hasNext();) { 75 KeyValuePairModell keyValuePair = (KeyValuePairModell) iter.next(); 76 if (keyValuePair.fKey.equals(key)) { 77 KeyValuePairModell next = (KeyValuePairModell) iter.next(); 78 return new DeleteEdit(keyValuePair.fOffset, next.fOffset - keyValuePair.fOffset); 79 } 80 } 81 return null; 82 } 83 84 public ReplaceEdit replace(KeyValuePair toReplace, KeyValuePair replaceWith) { 85 for (Iterator iter = fKeyValuePairs.iterator(); iter.hasNext();) { 86 KeyValuePairModell keyValuePair = (KeyValuePairModell) iter.next(); 87 if (keyValuePair.fKey.equals(toReplace.getKey())) { 88 String newText = new KeyValuePairModell(replaceWith).getEncodedText(fLineDelimiter); 89 KeyValuePairModell next = (KeyValuePairModell) iter.next(); 90 int range = next.fOffset - keyValuePair.fOffset; 91 return new ReplaceEdit(keyValuePair.fOffset, range, newText); 92 } 93 } 94 return null; 95 } 96 97 private int findInsertPosition(KeyValuePairModell keyValuePair) { 98 int insertIndex = 0; 99 int maxMatch = Integer.MIN_VALUE; 100 for (int i=0; i<fKeyValuePairs.size(); i++) { 101 KeyValuePairModell element = (KeyValuePairModell) fKeyValuePairs.get(i); 102 int match = element.compareTo(keyValuePair); 103 if (match >= maxMatch) { 104 insertIndex = i; 105 maxMatch = match; 106 } 107 } 108 109 if (insertIndex < fKeyValuePairs.size() - 1) { 110 insertIndex++; 111 } 112 113 return insertIndex; 114 } 115 116 private void parsePropertyDocument(IDocument document) { 117 fKeyValuePairs = new ArrayList (); 118 119 SimpleLineReader reader = new SimpleLineReader(document); 120 int offset = 0; 121 String line = reader.readLine(); 122 int leadingWhiteSpaces = 0; 123 while (line != null) { 124 if (!SimpleLineReader.isCommentOrWhiteSpace(line)) { 125 int idx = getIndexOfSeparationCharacter(line); 126 if (idx != -1) { 127 String key= line.substring(0, idx); 128 String value= line.substring(idx + 1); 129 fKeyValuePairs.add(new KeyValuePairModell(key, value, offset, leadingWhiteSpaces)); 130 leadingWhiteSpaces = 0; 131 } 132 } else { 133 leadingWhiteSpaces += line.length(); 134 } 135 offset += line.length(); 136 line = reader.readLine(); 137 } 138 int lastLine= document.getNumberOfLines() - 1; 139 boolean needsNewLine= false; 140 try { 141 needsNewLine= !(document.getLineLength(lastLine) == 0); 142 } catch (BadLocationException ignore) { 143 } 145 LastKeyValuePair lastKeyValuePair = new LastKeyValuePair(offset, needsNewLine); 146 fKeyValuePairs.add(lastKeyValuePair); 147 } 148 149 private int getIndexOfSeparationCharacter(String line) { 150 int minIndex = -1; 151 int indexOfEven = line.indexOf('='); 152 int indexOfColumn = line.indexOf(':'); 153 int indexOfBlank = line.indexOf(' '); 154 155 if ((indexOfEven != -1) && (indexOfColumn != -1)) { 156 minIndex = Math.min(indexOfEven, indexOfColumn); 157 } else { 158 minIndex = Math.max(indexOfEven, indexOfColumn); 159 } 160 161 if ((minIndex != -1) && (indexOfBlank != -1)) { 162 minIndex = Math.min(minIndex, indexOfBlank); 163 } else { 164 minIndex = Math.max(minIndex, indexOfBlank); 165 } 166 167 return minIndex; 168 } 169 170 public static String unwindEscapeChars(String s){ 171 StringBuffer sb= new StringBuffer (s.length()); 172 int length= s.length(); 173 for (int i= 0; i < length; i++){ 174 char c= s.charAt(i); 175 sb.append(getUnwoundString(c)); 176 } 177 return sb.toString(); 178 } 179 180 public static String unwindValue(String value) { 181 return escapeLeadingWhiteSpaces(escapeCommentChars(unwindEscapeChars(value))); 182 } 183 184 private static String getUnwoundString(char c){ 185 switch(c){ 186 case '\b' : 187 return "\\b"; case '\t' : 189 return "\\t"; case '\n' : 191 return "\\n"; case '\f' : 193 return "\\f"; case '\r' : 195 return "\\r"; 197 203 case '\\' : 204 return "\\\\"; 206 212 default: 213 if (((c < 0x0020) || (c > 0x007e))){ 214 return new StringBuffer () 215 .append('\\') 216 .append('u') 217 .append(toHex((c >> 12) & 0xF)) 218 .append(toHex((c >> 8) & 0xF)) 219 .append(toHex((c >> 4) & 0xF)) 220 .append(toHex( c & 0xF)).toString(); 221 222 } else 223 return String.valueOf(c); 224 } 225 } 226 227 private static char toHex(int halfByte) { 228 return HEX_DIGITS[(halfByte & 0xF)]; 229 } 230 231 private static String escapeCommentChars(String string) { 232 StringBuffer sb = new StringBuffer (string.length() + 5); 233 for (int i = 0; i < string.length(); i++) { 234 char c = string.charAt(i); 235 switch (c) { 236 case '!': 237 sb.append("\\!"); break; 239 case '#': 240 sb.append("\\#"); break; 242 default: 243 sb.append(c); 244 } 245 } 246 return sb.toString(); 247 } 248 249 private static String escapeLeadingWhiteSpaces(String str) { 250 int firstNonWhiteSpace= findFirstNonWhiteSpace(str); 251 StringBuffer buf= new StringBuffer (firstNonWhiteSpace); 252 for (int i = 0; i < firstNonWhiteSpace; i++) { 253 buf.append('\\'); 254 buf.append(str.charAt(i)); 255 } 256 buf.append(str.substring(firstNonWhiteSpace)); 257 return buf.toString(); 258 } 259 260 263 private static int findFirstNonWhiteSpace(String s) { 264 for (int i = 0; i < s.length(); i++) { 265 if (!Character.isWhitespace(s.charAt(i))) 266 return i; 267 } 268 return s.length(); 269 } 270 271 private static class KeyValuePairModell extends KeyValuePair implements Comparable { 272 273 int fOffset; 274 int fLeadingWhiteSpaces; 275 276 public KeyValuePairModell(String key, String value, int offset, int leadingWhiteSpaces) { 277 super(key, value); 278 fOffset = offset; 279 fLeadingWhiteSpaces = leadingWhiteSpaces; 280 } 281 282 public KeyValuePairModell(KeyValuePair keyValuePair) { 283 super(keyValuePair.fKey, keyValuePair.fValue); 284 } 285 286 public String getEncodedText(String lineDelimiter) { 287 return PropertyFileDocumentModel.unwindEscapeChars(fKey) + '=' + PropertyFileDocumentModel.unwindValue(fValue) + lineDelimiter; 288 } 289 290 public int compareTo(Object o) { 291 int counter = 0; 292 String key = ((KeyValuePair) o).fKey; 293 int minLen = Math.min(key.length(), fKey.length()); 294 int diffLen = Math.abs(key.length() - fKey.length()); 295 for (int i=0; i<minLen; i++) { 296 if (key.charAt(i) == fKey.charAt(i)) { 297 counter++; 298 } else { 299 break; 300 } 301 } 302 return counter - diffLen; 303 } 304 } 305 306 310 private static class LastKeyValuePair extends KeyValuePairModell { 311 312 private boolean fNeedsNewLine; 313 314 public LastKeyValuePair(int offset, boolean needsNewLine) { 315 super("last", "key", offset, 0); fNeedsNewLine= needsNewLine; 317 } 318 public int compareTo(Object o) { 319 return 1; 320 } 321 public boolean needsNewLine() { 322 return fNeedsNewLine; 323 } 324 public void resetNeedsNewLine() { 325 fNeedsNewLine= false; 326 } 327 } 328 } 329 | Popular Tags |