]> git.uio.no Git - ifi-stolz-refaktor.git/blob - case-study/jdt-after/ui/org/eclipse/jdt/internal/ui/text/spelling/engine/DefaultSpellChecker.java
005a680682c402dc71ed129e9cd0284d491b692c
[ifi-stolz-refaktor.git] / case-study / jdt-after / ui / org / eclipse / jdt / internal / ui / text / spelling / engine / DefaultSpellChecker.java
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  *******************************************************************************/
11 package org.eclipse.jdt.internal.ui.text.spelling.engine;
12
13 import java.util.Collections;
14 import java.util.HashSet;
15 import java.util.Iterator;
16 import java.util.Locale;
17 import java.util.Set;
18
19 import org.eclipse.core.runtime.Assert;
20
21 import org.eclipse.jface.preference.IPreferenceStore;
22
23 import org.eclipse.jdt.ui.PreferenceConstants;
24
25
26 /**
27  * Default spell checker for standard text.
28  *
29  * @since 3.0
30  */
31 public 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 }