421557685443a7bf34c6761cf492c4cc34980c44
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / text / spelling / SpellCheckEngine.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11
12 package net.sourceforge.phpdt.internal.ui.text.spelling;
13
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.net.MalformedURLException;
17 import java.net.URL;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.Iterator;
21 import java.util.Locale;
22 import java.util.Map;
23 import java.util.Set;
24
25 import net.sourceforge.phpdt.internal.ui.PHPUIMessages;
26 import net.sourceforge.phpdt.internal.ui.text.spelling.engine.DefaultSpellChecker;
27 import net.sourceforge.phpdt.internal.ui.text.spelling.engine.ISpellCheckEngine;
28 import net.sourceforge.phpdt.internal.ui.text.spelling.engine.ISpellCheckPreferenceKeys;
29 import net.sourceforge.phpdt.internal.ui.text.spelling.engine.ISpellChecker;
30 import net.sourceforge.phpdt.internal.ui.text.spelling.engine.ISpellDictionary;
31 import net.sourceforge.phpdt.internal.ui.text.spelling.engine.PersistentSpellDictionary;
32 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
33
34 import org.eclipse.jface.preference.IPreferenceStore;
35 import org.eclipse.jface.util.IPropertyChangeListener;
36 import org.eclipse.jface.util.PropertyChangeEvent;
37
38
39
40 /**
41  * Spell check engine for Java source spell checking.
42  * 
43  * @since 3.0
44  */
45 public class SpellCheckEngine implements ISpellCheckEngine, IPropertyChangeListener {
46
47         /** The dictionary location */
48         public static final String DICTIONARY_LOCATION= "dictionaries/"; //$NON-NLS-1$
49
50         /** The singleton spell checker instance */
51         private static ISpellChecker fChecker= null;
52
53         /** The singleton engine instance */
54         private static ISpellCheckEngine fEngine= null;
55
56         /**
57          * Returns the available locales for this spell check engine.
58          * 
59          * @return The available locales for this engine
60          */
61         public static Set getAvailableLocales() {
62
63                 URL url= null;
64                 Locale locale= null;
65                 InputStream stream= null;
66
67                 final Set result= new HashSet();
68                 try {
69
70                         final URL location= getDictionaryLocation();
71                         final Locale[] locales= Locale.getAvailableLocales();
72
73                         for (int index= 0; index < locales.length; index++) {
74
75                                 locale= locales[index];
76                                 url= new URL(location, locale.toString().toLowerCase() + "." + PHPUIMessages.getString("Spelling.dictionary.file.extension")); //$NON-NLS-1$ //$NON-NLS-2$
77
78                                 try {
79                                         stream= url.openStream();
80                                         if (stream != null) {
81                                                 try {
82                                                         result.add(locale);
83                                                 } finally {
84                                                         stream.close();
85                                                 }
86                                         }
87                                 } catch (IOException exception) {
88                                         // Do nothing
89                                 }
90                         }
91                 } catch (MalformedURLException exception) {
92                         // Do nothing
93                 }
94                 result.add(getDefaultLocale());
95
96                 return result;
97         }
98
99         /**
100          * Returns the default locale for this engine.
101          * 
102          * @return The default locale
103          */
104         public static Locale getDefaultLocale() {
105                 return Locale.US;
106         }
107
108         /**
109          * Returns the dictionary location.
110          * 
111          * @throws MalformedURLException
112          *                    if the URL could not be created
113          * @return The dictionary location, or <code>null</code> iff the location
114          *               is not known
115          */
116         public static URL getDictionaryLocation() throws MalformedURLException {
117
118                 final PHPeclipsePlugin plugin= PHPeclipsePlugin.getDefault();
119                 if (plugin != null)
120                         return plugin.getBundle().getEntry("/" + DICTIONARY_LOCATION); //$NON-NLS-1$
121
122                 return null;
123         }
124
125         /**
126          * Returns the singleton instance of the spell check engine.
127          * 
128          * @return The singleton instance of the spell check engine
129          */
130         public static final synchronized ISpellCheckEngine getInstance() {
131
132                 if (fEngine == null)
133                         fEngine= new SpellCheckEngine();
134
135                 return fEngine;
136         }
137
138         /** The registered locale insenitive dictionaries */
139         private final Set fGlobalDictionaries= new HashSet();
140
141         /** The current locale */
142         private Locale fLocale= null;
143
144         /** The registered locale sensitive dictionaries */
145         private final Map fLocaleDictionaries= new HashMap();
146
147         /** The preference store where to listen */
148         private IPreferenceStore fPreferences= null;
149
150         /** The user dictionary */
151         private ISpellDictionary fUserDictionary= null;
152
153         /**
154          * Creates a new spell check manager.
155          */
156         private SpellCheckEngine() {
157
158                 fGlobalDictionaries.add(new TaskTagDictionary());
159                 fGlobalDictionaries.add(new HtmlTagDictionary());
160                 fGlobalDictionaries.add(new JavaDocTagDictionary());
161
162                 try {
163
164                         Locale locale= null;
165                         final URL location= getDictionaryLocation();
166
167                         for (final Iterator iterator= getAvailableLocales().iterator(); iterator.hasNext();) {
168
169                                 locale= (Locale)iterator.next();
170                                 fLocaleDictionaries.put(locale, new SpellReconcileDictionary(locale, location));
171                         }
172
173                 } catch (MalformedURLException exception) {
174                         // Do nothing
175                 }
176         }
177
178         /*
179          * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellCheckEngine#createSpellChecker(java.util.Locale,org.eclipse.jface.preference.IPreferenceStore)
180          */
181         public final synchronized ISpellChecker createSpellChecker(final Locale locale, final IPreferenceStore store) {
182
183                 if (fLocale != null && fLocale.equals(locale))
184                         return fChecker;
185
186                 if (fChecker == null) {
187
188                         fChecker= new DefaultSpellChecker(store);
189                         store.addPropertyChangeListener(this);
190
191                         fPreferences= store;
192
193                         ISpellDictionary dictionary= null;
194                         for (Iterator iterator= fGlobalDictionaries.iterator(); iterator.hasNext();) {
195
196                                 dictionary= (ISpellDictionary)iterator.next();
197                                 fChecker.addDictionary(dictionary);
198                         }
199                 }
200
201                 ISpellDictionary dictionary= null;
202                 if (fLocale != null) {
203
204                         dictionary= (ISpellDictionary)fLocaleDictionaries.get(fLocale);
205                         if (dictionary != null) {
206
207                                 fChecker.removeDictionary(dictionary);
208                                 dictionary.unload();
209                         }
210                 }
211                 fLocale= locale;
212
213                 dictionary= (ISpellDictionary)fLocaleDictionaries.get(locale);
214                 if (dictionary == null) {
215
216                         if (!getDefaultLocale().equals(locale)) {
217
218                                 if (fPreferences != null)
219                                         fPreferences.removePropertyChangeListener(this);
220
221                                 fChecker= null;
222                                 fLocale= null;
223                         }
224
225                 } else
226                         fChecker.addDictionary(dictionary);
227
228                 if (fPreferences != null)
229                         propertyChange(new PropertyChangeEvent(this, ISpellCheckPreferenceKeys.SPELLING_USER_DICTIONARY, null, fPreferences.getString(ISpellCheckPreferenceKeys.SPELLING_USER_DICTIONARY)));
230
231                 return fChecker;
232         }
233
234         /*
235          * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellCheckEngine#getLocale()
236          */
237         public final Locale getLocale() {
238                 return fLocale;
239         }
240
241         /*
242          * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
243          */
244         public final void propertyChange(final PropertyChangeEvent event) {
245
246                 if (fChecker != null && event.getProperty().equals(ISpellCheckPreferenceKeys.SPELLING_USER_DICTIONARY)) {
247
248                         if (fUserDictionary != null) {
249
250                                 fChecker.removeDictionary(fUserDictionary);
251                                 fUserDictionary= null;
252                         }
253
254                         final String file= (String)event.getNewValue();
255                         if (file.length() > 0) {
256
257                                 try {
258
259                                         final URL url= new URL("file", null, file); //$NON-NLS-1$
260                                         InputStream stream= url.openStream();
261                                         if (stream != null) {
262                                                 try {
263                                                         fUserDictionary= new PersistentSpellDictionary(url);
264                                                         fChecker.addDictionary(fUserDictionary);
265                                                 } finally {
266                                                         stream.close();
267                                                 }
268                                         }
269                                 } catch (MalformedURLException exception) {
270                                         // Do nothing
271                                 } catch (IOException exception) {
272                                         // Do nothing
273                                 }
274                         }
275                 }
276         }
277
278         /*
279          * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellCheckEngine#registerDictionary(org.eclipse.jdt.ui.text.spelling.engine.ISpellDictionary)
280          */
281         public synchronized final void registerDictionary(final ISpellDictionary dictionary) {
282
283                 fGlobalDictionaries.add(dictionary);
284
285                 if (fChecker != null)
286                         fChecker.addDictionary(dictionary);
287         }
288
289         /*
290          * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellCheckEngine#registerDictionary(java.util.Locale,org.eclipse.jdt.ui.text.spelling.engine.ISpellDictionary)
291          */
292         public synchronized final void registerDictionary(final Locale locale, final ISpellDictionary dictionary) {
293
294                 fLocaleDictionaries.put(locale, dictionary);
295
296                 if (fChecker != null && fLocale != null && fLocale.equals(locale))
297                         fChecker.addDictionary(dictionary);
298         }
299
300         /*
301          * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellCheckEngine#unload()
302          */
303         public synchronized final void unload() {
304
305                 ISpellDictionary dictionary= null;
306                 for (final Iterator iterator= fGlobalDictionaries.iterator(); iterator.hasNext();) {
307
308                         dictionary= (ISpellDictionary)iterator.next();
309                         dictionary.unload();
310                 }
311
312                 for (final Iterator iterator= fLocaleDictionaries.values().iterator(); iterator.hasNext();) {
313
314                         dictionary= (ISpellDictionary)iterator.next();
315                         dictionary.unload();
316                 }
317
318                 if (fPreferences != null)
319                         fPreferences.removePropertyChangeListener(this);
320
321                 fUserDictionary= null;
322                 fChecker= null;
323         }
324
325         /*
326          * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellCheckEngine#unregisterDictionary(org.eclipse.jdt.ui.text.spelling.engine.ISpellDictionary)
327          */
328         public synchronized final void unregisterDictionary(final ISpellDictionary dictionary) {
329
330                 fGlobalDictionaries.remove(dictionary);
331                 fLocaleDictionaries.values().remove(dictionary);
332
333                 if (fChecker != null)
334                         fChecker.removeDictionary(dictionary);
335
336                 dictionary.unload();
337         }
338 }