]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-after/ui/org/eclipse/jdt/internal/ui/text/spelling/engine/DefaultSpellChecker.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-after / ui / org / eclipse / jdt / internal / ui / text / spelling / engine / DefaultSpellChecker.java
CommitLineData
1b2798f6
EK
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
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11package org.eclipse.jdt.internal.ui.text.spelling.engine;
12
13import java.util.Collections;
14import java.util.HashSet;
15import java.util.Iterator;
16import java.util.Locale;
17import java.util.Set;
18
19import org.eclipse.core.runtime.Assert;
20
21import org.eclipse.jface.preference.IPreferenceStore;
22
23import org.eclipse.jdt.ui.PreferenceConstants;
24
25
26/**
27 * Default spell checker for standard text.
28 *
29 * @since 3.0
30 */
31public class DefaultSpellChecker implements ISpellChecker {
32
33 /** Array of URL prefixes */
34 public static final String[] URL_PREFIXES= new String[] { "http://", "https://", "www.", "ftp://", "ftps://", "news://", "mailto://" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
35
36 /**
37 * Does this word contain digits?
38 *
39 * @param word the word to check
40 * @return <code>true</code> iff this word contains digits, <code>false></code> otherwise
41 */
42 protected static boolean isDigits(final String word) {
43
44 for (int index= 0; index < word.length(); index++) {
45
46 if (Character.isDigit(word.charAt(index)))
47 return true;
48 }
49 return false;
50 }
51
52 /**
53 * Does this word contain mixed-case letters?
54 *
55 * @param word
56 * The word to check
57 * @param sentence
58 * <code>true</code> iff the specified word starts a new
59 * sentence, <code>false</code> otherwise
60 * @return <code>true</code> iff the contains mixed-case letters, <code>false</code>
61 * otherwise
62 */
63 protected static boolean isMixedCase(final String word, final boolean sentence) {
64
65 final int length= word.length();
66 boolean upper= Character.isUpperCase(word.charAt(0));
67
68 if (sentence && upper && (length > 1))
69 upper= Character.isUpperCase(word.charAt(1));
70
71 if (upper) {
72
73 for (int index= length - 1; index > 0; index--) {
74 if (Character.isLowerCase(word.charAt(index)))
75 return true;
76 }
77 } else {
78
79 for (int index= length - 1; index > 0; index--) {
80 if (Character.isUpperCase(word.charAt(index)))
81 return true;
82 }
83 }
84 return false;
85 }
86
87 /**
88 * Does this word contain upper-case letters only?
89 *
90 * @param word
91 * The word to check
92 * @return <code>true</code> iff this word only contains upper-case
93 * letters, <code>false</code> otherwise
94 */
95 protected static boolean isUpperCase(final String word) {
96
97 for (int index= word.length() - 1; index >= 0; index--) {
98
99 if (Character.isLowerCase(word.charAt(index)))
100 return false;
101 }
102 return true;
103 }
104
105 /**
106 * Does this word look like an URL?
107 *
108 * @param word
109 * The word to check
110 * @return <code>true</code> iff this word looks like an URL, <code>false</code>
111 * otherwise
112 */
113 protected static boolean isUrl(final String word) {
114
115 for (int index= 0; index < URL_PREFIXES.length; index++) {
116
117 if (word.startsWith(URL_PREFIXES[index]))
118 return true;
119 }
120 return false;
121 }
122
123 /**
124 * The dictionaries to use for spell checking. Synchronized to avoid
125 * concurrent modifications.
126 */
127 private final Set<ISpellDictionary> fDictionaries= Collections.synchronizedSet(new HashSet<ISpellDictionary>());
128
129 /**
130 * The words to be ignored. Synchronized to avoid concurrent modifications.
131 */
132 private final Set<String> fIgnored= Collections.synchronizedSet(new HashSet<String>());
133
134 /**
135 * The preference store. Assumes the <code>IPreferenceStore</code>
136 * implementation is thread safe.
137 */
138 private final IPreferenceStore fPreferences;
139
140 /**
141 * The locale of this checker.
142 * @since 3.3
143 */
144 private Locale fLocale;
145
146 /**
147 * Creates a new default spell checker.
148 *
149 * @param store the preference store for this spell checker
150 * @param locale the locale
151 */
152 public DefaultSpellChecker(IPreferenceStore store, Locale locale) {
153 Assert.isLegal(store != null);
154 Assert.isLegal(locale != null);
155
156 fPreferences= store;
157 fLocale= locale;
158 }
159
160 /*
161 * @see org.eclipse.spelling.done.ISpellChecker#addDictionary(org.eclipse.spelling.done.ISpellDictionary)
162 */
163 public final void addDictionary(final ISpellDictionary dictionary) {
164 // synchronizing is necessary as this is a write access
165 fDictionaries.add(dictionary);
166 }
167
168 /*
169 * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellChecker#acceptsWords()
170 */
171 public boolean acceptsWords() {
172 // synchronizing might not be needed here since acceptWords is
173 // a read-only access and only called in the same thread as
174 // the modifying methods add/checkWord (?)
175 Set<ISpellDictionary> copy;
176 synchronized (fDictionaries) {
177 copy= new HashSet<ISpellDictionary>(fDictionaries);
178 }
179
180 ISpellDictionary dictionary= null;
181 for (final Iterator<ISpellDictionary> iterator= copy.iterator(); iterator.hasNext();) {
182
183 dictionary= iterator.next();
184 if (dictionary.acceptsWords())
185 return true;
186 }
187 return false;
188 }
189
190 /*
191 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker#addWord(java.lang.String)
192 */
193 public void addWord(final String word) {
194 // synchronizing is necessary as this is a write access
195 Set<ISpellDictionary> copy;
196 synchronized (fDictionaries) {
197 copy= new HashSet<ISpellDictionary>(fDictionaries);
198 }
199
200 final String addable= word.toLowerCase();
201 for (final Iterator<ISpellDictionary> iterator= copy.iterator(); iterator.hasNext();) {
202 ISpellDictionary dictionary= iterator.next();
203 if (dictionary.acceptsWords())
204 dictionary.addWord(addable);
205 }
206
207 }
208
209 /*
210 * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellChecker#checkWord(java.lang.String)
211 */
212 public final void checkWord(final String word) {
213 // synchronizing is necessary as this is a write access
214 fIgnored.remove(word.toLowerCase());
215 }
216
217 /*
218 * @see org.eclipse.spelling.done.ISpellChecker#execute(org.eclipse.spelling.ISpellCheckTokenizer)
219 */
220 public void execute(final ISpellEventListener listener, final ISpellCheckIterator iterator) {
221
222 final boolean ignoreDigits= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_DIGITS);
223 final boolean ignoreMixed= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_MIXED);
224 final boolean ignoreSentence= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_SENTENCE);
225 final boolean ignoreUpper= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_UPPER);
226 final boolean ignoreURLS= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_URLS);
227 final boolean ignoreNonLetters= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_NON_LETTERS);
228 final boolean ignoreSingleLetters= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_SINGLE_LETTERS);
229 final int problemsThreshold= PreferenceConstants.getPreferenceStore().getInt(PreferenceConstants.SPELLING_PROBLEMS_THRESHOLD);
230
231 iterator.setIgnoreSingleLetters(ignoreSingleLetters);
232
233 Iterator<ISpellDictionary> iter= fDictionaries.iterator();
234 while (iter.hasNext())
235 iter.next().setStripNonLetters(ignoreNonLetters);
236
237 String word= null;
238 boolean starts= false;
239 int problemCount= 0;
240
241 while (problemCount <= problemsThreshold && iterator.hasNext()) {
242
243 word= iterator.next();
244 if (word != null) {
245
246 // synchronizing is necessary as this is called inside the reconciler
247 if (!fIgnored.contains(word)) {
248
249 starts= iterator.startsSentence();
250 if (!isCorrect(word)) {
251
252 boolean isMixed= isMixedCase(word, true);
253 boolean isUpper= isUpperCase(word);
254 boolean isDigits= isDigits(word);
255 boolean isURL= isUrl(word);
256
257 if ( !ignoreMixed && isMixed || !ignoreUpper && isUpper || !ignoreDigits && isDigits || !ignoreURLS && isURL || !(isMixed || isUpper || isDigits || isURL)) {
258 listener.handle(new SpellEvent(this, word, iterator.getBegin(), iterator.getEnd(), starts, false));
259 problemCount++;
260 }
261
262 } else {
263
264 if (!ignoreSentence && starts && Character.isLowerCase(word.charAt(0))) {
265 listener.handle(new SpellEvent(this, word, iterator.getBegin(), iterator.getEnd(), true, true));
266 problemCount++;
267 }
268 }
269 }
270 }
271 }
272 }
273
274 /*
275 * @see org.eclipse.spelling.done.ISpellChecker#getProposals(java.lang.String,boolean)
276 */
277 public Set<RankedWordProposal> getProposals(final String word, final boolean sentence) {
278
279 // synchronizing might not be needed here since getProposals is
280 // a read-only access and only called in the same thread as
281 // the modifing methods add/removeDictionary (?)
282 Set<ISpellDictionary> copy;
283 synchronized (fDictionaries) {
284 copy= new HashSet<ISpellDictionary>(fDictionaries);
285 }
286
287 ISpellDictionary dictionary= null;
288 final HashSet<RankedWordProposal> proposals= new HashSet<RankedWordProposal>();
289
290 for (final Iterator<ISpellDictionary> iterator= copy.iterator(); iterator.hasNext();) {
291
292 dictionary= iterator.next();
293 proposals.addAll(dictionary.getProposals(word, sentence));
294 }
295 return proposals;
296 }
297
298 /*
299 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker#ignoreWord(java.lang.String)
300 */
301 public final void ignoreWord(final String word) {
302 // synchronizing is necessary as this is a write access
303 fIgnored.add(word.toLowerCase());
304 }
305
306 /*
307 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker#isCorrect(java.lang.String)
308 */
309 public final boolean isCorrect(final String word) {
310 // synchronizing is necessary as this is called from execute
311 Set<ISpellDictionary> copy;
312 synchronized (fDictionaries) {
313 copy= new HashSet<ISpellDictionary>(fDictionaries);
314 }
315
316 if (fIgnored.contains(word.toLowerCase()))
317 return true;
318
319 ISpellDictionary dictionary= null;
320 for (final Iterator<ISpellDictionary> iterator= copy.iterator(); iterator.hasNext();) {
321
322 dictionary= iterator.next();
323 if (dictionary.isCorrect(word))
324 return true;
325 }
326 return false;
327 }
328
329 /*
330 * @see org.eclipse.spelling.done.ISpellChecker#removeDictionary(org.eclipse.spelling.done.ISpellDictionary)
331 */
332 public final void removeDictionary(final ISpellDictionary dictionary) {
333 // synchronizing is necessary as this is a write access
334 fDictionaries.remove(dictionary);
335 }
336
337 /*
338 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker#getLocale()
339 * @since 3.3
340 */
341 public Locale getLocale() {
342 return fLocale;
343 }
344}