1 /*******************************************************************************
2 * Copyright (c) 2000, 2011 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.corext.refactoring.nls;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.Collections;
16 import java.util.Comparator;
17 import java.util.Iterator;
18 import java.util.List;
20 import com.ibm.icu.text.Collator;
22 import org.eclipse.text.edits.DeleteEdit;
23 import org.eclipse.text.edits.InsertEdit;
24 import org.eclipse.text.edits.ReplaceEdit;
26 import org.eclipse.jface.text.IDocument;
27 import org.eclipse.jface.text.TextUtilities;
29 import org.eclipse.ltk.core.refactoring.TextChange;
31 import org.eclipse.jdt.internal.ui.propertiesfileeditor.PropertiesFileEscapes;
33 public class PropertyFileDocumentModel {
35 List<KeyValuePairModell> fKeyValuePairs;
36 private String fLineDelimiter;
38 public PropertyFileDocumentModel(IDocument document) {
39 parsePropertyDocument(document);
40 fLineDelimiter= TextUtilities.getDefaultLineDelimiter(document);
44 * @return the line delimiter used by the document described by this model
46 public String getLineDelimiter() {
47 return fLineDelimiter;
51 * Return the key value pair in this model with the key <code>key</code>
53 * @param key the key of the pair
54 * @return the pair with the key or <b>null</b> if no such pair.
56 public KeyValuePair getKeyValuePair(String key) {
57 for (int i= 0; i < fKeyValuePairs.size(); i++) {
58 KeyValuePairModell keyValuePair = fKeyValuePairs.get(i);
59 if (keyValuePair.getKey().equals(key)) {
66 InsertEdit insert(KeyValuePair keyValuePair) {
67 KeyValuePairModell keyValuePairModell = new KeyValuePairModell(keyValuePair);
68 int index = findInsertPosition(keyValuePairModell);
69 KeyValuePairModell insertHere = fKeyValuePairs.get(index);
70 int offset = insertHere.fOffset;
72 String extra= ""; //$NON-NLS-1$
73 if (insertHere instanceof LastKeyValuePair && ((LastKeyValuePair)insertHere).needsNewLine()) {
74 extra= fLineDelimiter;
75 ((LastKeyValuePair)insertHere).resetNeedsNewLine();
76 offset-= insertHere.fLeadingWhiteSpaces;
77 } else if (index > 0) {
78 String beforeKey= fKeyValuePairs.get(index - 1).fKey;
79 String afterKey= insertHere.fKey;
80 String key= keyValuePair.fKey;
81 int distBefore= NLSUtil.invertDistance(key, beforeKey);
82 int distAfter= NLSUtil.invertDistance(key, afterKey);
83 if (distBefore > distAfter) {
84 offset-= insertHere.fLeadingWhiteSpaces;
85 } else if (distBefore == distAfter && Collator.getInstance().compare(beforeKey, afterKey) < 0) {
86 offset-= insertHere.fLeadingWhiteSpaces;
88 //insert it before afterKey -> move the leading white spaces to the inserted pair
89 keyValuePairModell.fLeadingWhiteSpaces= insertHere.fLeadingWhiteSpaces;
90 insertHere.fLeadingWhiteSpaces= 0;
94 String text= keyValuePairModell.generated_875148158285524824(this, index, offset, extra);
95 return new InsertEdit(offset, text);
99 * Inserts the given key value pairs into this model at appropriate
100 * positions. Records all required text changes in the given change
102 * @param keyValuePairs the key value pairs to insert
103 * @param change the change to use to record text changes
105 public void insert(KeyValuePair[] keyValuePairs, TextChange change) {
107 ArrayList<KeyValuePair> sorted= new ArrayList<KeyValuePair>(Arrays.asList(keyValuePairs));
108 Collections.sort(sorted, new Comparator<KeyValuePair>() {
109 public int compare(KeyValuePair p1, KeyValuePair p2) {
110 return Collator.getInstance().compare(p1.fKey, p2.fKey);
114 for (int i = 0; i < sorted.size(); i++) {
115 KeyValuePair curr= sorted.get(i);
116 curr.generated_45942992453355874(change, this);
120 public DeleteEdit remove(String key) {
121 for (Iterator<KeyValuePairModell> iter = fKeyValuePairs.iterator(); iter.hasNext();) {
122 KeyValuePairModell keyValuePair = iter.next();
123 if (keyValuePair.fKey.equals(key)) {
124 return keyValuePair.generated_6789650072710353462(this);
130 public ReplaceEdit replace(KeyValuePair toReplace, KeyValuePair replaceWith) {
131 for (Iterator<KeyValuePairModell> iter = fKeyValuePairs.iterator(); iter.hasNext();) {
132 KeyValuePairModell keyValuePair = iter.next();
133 if (keyValuePair.fKey.equals(toReplace.getKey())) {
134 String newText= new KeyValuePairModell(replaceWith).getKeyValueText();
135 return keyValuePair.generated_6698145679089660767(this, newText);
141 private int findInsertPosition(KeyValuePairModell keyValuePair) {
142 ArrayList<String> keys= new ArrayList<String>();
143 for (int i= 0; i < fKeyValuePairs.size(); i++) {
144 KeyValuePairModell element = fKeyValuePairs.get(i);
145 element.generated_326054000021849204(keys);
147 int insertIndex= NLSUtil.getInsertionPosition(keyValuePair.getKey(), keys);
149 if (insertIndex < fKeyValuePairs.size() - 1) {
156 private void parsePropertyDocument(IDocument document) {
157 fKeyValuePairs = new ArrayList<KeyValuePairModell>();
159 SimpleLineReader reader = new SimpleLineReader(document);
161 LastKeyValuePair lastKeyValuePair= reader.generated_689189764367573075(document, this, offset);
162 fKeyValuePairs.add(lastKeyValuePair);
165 int getIndexOfSeparationCharacter(String line) {
167 int indexOfEven = line.indexOf('=');
168 int indexOfColumn = line.indexOf(':');
169 int indexOfBlank = line.indexOf(' ');
171 if ((indexOfEven != -1) && (indexOfColumn != -1)) {
172 minIndex = Math.min(indexOfEven, indexOfColumn);
174 minIndex = Math.max(indexOfEven, indexOfColumn);
177 if ((minIndex == -1) && (indexOfBlank != -1)) {
178 minIndex= indexOfBlank;
184 public static String escape(String s, boolean escapeCommentCharsAndLeadingWhitespaces) {
185 StringBuffer sb= new StringBuffer(s.length());
186 int length= s.length();
187 for (int i= 0; i < length; i++){
189 sb.append(PropertiesFileEscapes.escape(c));
191 if(!escapeCommentCharsAndLeadingWhitespaces)
192 return sb.toString();
193 return escapeLeadingWhiteSpaces(escapeCommentChars(sb.toString()));
196 private static String escapeCommentChars(String string) {
197 StringBuffer sb = new StringBuffer(string.length() + 5);
198 for (int i = 0; i < string.length(); i++) {
199 char c = string.charAt(i);
202 sb.append("\\!"); //$NON-NLS-1$
205 sb.append("\\#"); //$NON-NLS-1$
211 return sb.toString();
214 private static String escapeLeadingWhiteSpaces(String str) {
215 int firstNonWhiteSpace= findFirstNonWhiteSpace(str);
216 StringBuffer buf= new StringBuffer(firstNonWhiteSpace);
217 for (int i = 0; i < firstNonWhiteSpace; i++) {
219 buf.append(str.charAt(i));
221 buf.append(str.substring(firstNonWhiteSpace));
222 return buf.toString();
226 * @param s the string to inspect
227 * @return the first non whitespace character, the length if only whitespace characters
229 private static int findFirstNonWhiteSpace(String s) {
230 for (int i = 0; i < s.length(); i++) {
231 if (!Character.isWhitespace(s.charAt(i)))
237 static class KeyValuePairModell extends KeyValuePair {
241 int fLeadingWhiteSpaces;
243 public KeyValuePairModell(String key, String value, int offset, int length, int leadingWhiteSpaces) {
247 fLeadingWhiteSpaces = leadingWhiteSpaces;
250 public KeyValuePairModell(KeyValuePair keyValuePair) {
251 super(keyValuePair.fKey, keyValuePair.fValue);
254 public int getLength() {
258 String getKeyValueText() {
259 return fKey + '=' + fValue;
262 public String generated_875148158285524824(PropertyFileDocumentModel propertyfiledocumentmodel, int index, int offset, String extra) {
263 String text= extra + getKeyValueText();
265 fLength= text.length();
266 propertyfiledocumentmodel.fKeyValuePairs.add(index, this);
270 public DeleteEdit generated_6789650072710353462(PropertyFileDocumentModel propertyfiledocumentmodel) {
271 return new DeleteEdit(fOffset, getLength());
274 public ReplaceEdit generated_6698145679089660767(PropertyFileDocumentModel propertyfiledocumentmodel, String newText) {
275 return new ReplaceEdit(fOffset, getLength(), newText);
278 public void generated_326054000021849204(ArrayList<String> keys) {
279 if (! (this instanceof LastKeyValuePair))
285 * anchor element for a list of KeyValuePairs. (it is greater than every
286 * other KeyValuePair)
288 static class LastKeyValuePair extends KeyValuePairModell {
290 private boolean fNeedsNewLine;
292 public LastKeyValuePair(int offset, boolean needsNewLine) {
293 super("zzzzzzz", "key", offset, 7 + 1 + 3, 0); //$NON-NLS-1$ //$NON-NLS-2$
294 fNeedsNewLine= needsNewLine;
296 public boolean needsNewLine() {
297 return fNeedsNewLine;
299 public void resetNeedsNewLine() {
300 fNeedsNewLine= false;