RC2 compatibility
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / text / spelling / SpellReconcileStrategy.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.text.MessageFormat;
15 import java.util.Locale;
16
17 import net.sourceforge.phpdt.core.IProblemRequestor;
18 import net.sourceforge.phpdt.core.compiler.IProblem;
19 import net.sourceforge.phpdt.internal.ui.PHPUIMessages;
20 import net.sourceforge.phpdt.internal.ui.text.spelling.engine.ISpellCheckEngine;
21 import net.sourceforge.phpdt.internal.ui.text.spelling.engine.ISpellCheckPreferenceKeys;
22 import net.sourceforge.phpdt.internal.ui.text.spelling.engine.ISpellChecker;
23 import net.sourceforge.phpdt.internal.ui.text.spelling.engine.ISpellEvent;
24 import net.sourceforge.phpdt.internal.ui.text.spelling.engine.ISpellEventListener;
25
26 import org.eclipse.core.runtime.IProgressMonitor;
27 import org.eclipse.jface.preference.IPreferenceStore;
28 import org.eclipse.jface.text.BadLocationException;
29 import org.eclipse.jface.text.IDocument;
30 import org.eclipse.jface.text.IRegion;
31 import org.eclipse.jface.text.ITypedRegion;
32 import org.eclipse.jface.text.TextUtilities;
33 import org.eclipse.jface.text.reconciler.DirtyRegion;
34 import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
35 import org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension;
36 import org.eclipse.jface.text.source.IAnnotationModel;
37 import org.eclipse.ui.texteditor.ITextEditor;
38
39 /**
40  * Reconcile strategy to spell-check comments.
41  * 
42  * @since 3.0
43  */
44 public class SpellReconcileStrategy implements IReconcilingStrategy, IReconcilingStrategyExtension, ISpellEventListener {
45
46         /**
47          * Spelling problem to be accepted by problem requestors.
48          */
49         public class SpellProblem implements IProblem {
50
51                 /** The id of the problem */
52                 public static final int Spelling= 0x80000000;
53
54                 /** The end offset of the problem */
55                 private int fEnd= 0;
56
57                 /** The line number of the problem */
58                 private int fLine= 1;
59
60                 /** Was the word found in the dictionary? */
61                 private boolean fMatch;
62
63                 /** Does the word start a new sentence? */
64                 private boolean fSentence= false;
65
66                 /** The start offset of the problem */
67                 private int fStart= 0;
68
69                 /** The word which caused the problem */
70                 private final String fWord;
71
72                 /**
73                  * Creates a new spelling problem
74                  * 
75                  * @param word
76                  *                   The word which caused the problem
77                  */
78                 protected SpellProblem(final String word) {
79                         fWord= word;
80                 }
81
82                 /*
83                  * @see org.eclipse.jdt.core.compiler.IProblem#getArguments()
84                  */
85                 public String[] getArguments() {
86
87                         String prefix= ""; //$NON-NLS-1$
88                         String postfix= ""; //$NON-NLS-1$
89
90                         try {
91
92                                 final IRegion line= fDocument.getLineInformationOfOffset(fStart);
93
94                                 prefix= fDocument.get(line.getOffset(), fStart - line.getOffset());
95                                 postfix= fDocument.get(fEnd + 1, line.getOffset() + line.getLength() - fEnd);
96
97                         } catch (BadLocationException exception) {
98                                 // Do nothing
99                         }
100                         return new String[] { fWord, prefix, postfix, fSentence ? Boolean.toString(true) : Boolean.toString(false), fMatch ? Boolean.toString(true) : Boolean.toString(false)};
101                 }
102
103                 /*
104                  * @see org.eclipse.jdt.core.compiler.IProblem#getID()
105                  */
106                 public int getID() {
107                         return Spelling;
108                 }
109
110                 /*
111                  * @see org.eclipse.jdt.core.compiler.IProblem#getMessage()
112                  */
113                 public String getMessage() {
114
115                         if (fSentence && fMatch)
116                                 return MessageFormat.format(PHPUIMessages.getString("Spelling.error.case.label"), new String[] { fWord }); //$NON-NLS-1$
117
118                         return MessageFormat.format(PHPUIMessages.getString("Spelling.error.label"), new String[] { fWord }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
119                 }
120
121                 /*
122                  * @see org.eclipse.jdt.core.compiler.IProblem#getOriginatingFileName()
123                  */
124                 public char[] getOriginatingFileName() {
125                         return fEditor.getEditorInput().getName().toCharArray();
126                 }
127
128                 /*
129                  * @see org.eclipse.jdt.core.compiler.IProblem#getSourceEnd()
130                  */
131                 public final int getSourceEnd() {
132                         return fEnd;
133                 }
134
135                 /*
136                  * @see org.eclipse.jdt.core.compiler.IProblem#getSourceLineNumber()
137                  */
138                 public final int getSourceLineNumber() {
139                         return fLine;
140                 }
141
142                 /*
143                  * @see org.eclipse.jdt.core.compiler.IProblem#getSourceStart()
144                  */
145                 public final int getSourceStart() {
146                         return fStart;
147                 }
148
149                 /**
150                  * Was the problem word found in the dictionary?
151                  * 
152                  * @return <code>true</code> iff the word was found, <code>false</code>
153                  *               otherwise
154                  */
155                 public final boolean isDictionaryMatch() {
156                         return fMatch;
157                 }
158
159                 /*
160                  * @see org.eclipse.jdt.core.compiler.IProblem#isError()
161                  */
162                 public final boolean isError() {
163                         return false;
164                 }
165
166                 /**
167                  * Does the problem word start a new sentence?
168                  * 
169                  * @return <code>true</code> iff it starts a new sentence, <code>false</code>
170                  *               otherwise
171                  */
172                 public final boolean isSentenceStart() {
173                         return fSentence;
174                 }
175
176                 /*
177                  * @see org.eclipse.jdt.core.compiler.IProblem#isWarning()
178                  */
179                 public final boolean isWarning() {
180                         return true;
181                 }
182
183                 /**
184                  * Sets whether the problem word was found in the dictionary.
185                  * 
186                  * @param match
187                  *                   <code>true</code> iff the word was found, <code>false</code>
188                  *                   otherwise
189                  */
190                 public final void setDictionaryMatch(final boolean match) {
191                         fMatch= match;
192                 }
193
194                 /**
195                  * Sets whether the problem word starts a new sentence.
196                  * 
197                  * @param sentence
198                  *                   <code>true</code> iff the word starts a new sentence,
199                  *                   <code>false</code> otherwise.
200                  */
201                 public final void setSentenceStart(final boolean sentence) {
202                         fSentence= sentence;
203                 }
204
205                 /*
206                  * @see org.eclipse.jdt.core.compiler.IProblem#setSourceEnd(int)
207                  */
208                 public final void setSourceEnd(final int end) {
209                         fEnd= end;
210                 }
211
212                 /*
213                  * @see org.eclipse.jdt.core.compiler.IProblem#setSourceLineNumber(int)
214                  */
215                 public final void setSourceLineNumber(final int line) {
216                         fLine= line;
217                 }
218
219                 /*
220                  * @see org.eclipse.jdt.core.compiler.IProblem#setSourceStart(int)
221                  */
222                 public final void setSourceStart(final int start) {
223                         fStart= start;
224                 }
225         }
226
227         /** The document to operate on */
228         private IDocument fDocument= null;
229
230         /** The text editor to operate on */
231         private final ITextEditor fEditor;
232
233         /** The current locale */
234         private Locale fLocale= SpellCheckEngine.getDefaultLocale();
235
236         /** The partitioning of the document */
237         private final String fPartitioning;
238
239         /** The preference store to use */
240         private final IPreferenceStore fPreferences;
241
242         /** The problem requestor */
243         private IProblemRequestor fRequestor;
244
245         /**
246          * Creates a new comment reconcile strategy.
247          * 
248          * @param editor
249          *                   The text editor to operate on
250          * @param partitioning
251          *                   The partitioning of the document
252          * @param store
253          *                   The preference store to get the preferences from
254          */
255         public SpellReconcileStrategy(final ITextEditor editor, final String partitioning, final IPreferenceStore store) {
256                 fEditor= editor;
257                 fPartitioning= partitioning;
258                 fPreferences= store;
259
260                 updateProblemRequestor();
261         }
262
263         /**
264          * Returns the current locale of the spell checking preferences.
265          * 
266          * @return The current locale of the spell checking preferences
267          */
268         public Locale getLocale() {
269
270                 final String locale= fPreferences.getString(ISpellCheckPreferenceKeys.SPELLING_LOCALE);
271                 if (locale.equals(fLocale.toString()))
272                         return fLocale;
273
274                 if (locale.length() >= 5)
275                         return new Locale(locale.substring(0, 2), locale.substring(3, 5));
276
277                 return SpellCheckEngine.getDefaultLocale();
278         }
279
280         /*
281          * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEventListener#handle(org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEvent)
282          */
283         public void handle(final ISpellEvent event) {
284                 
285                 if (fRequestor != null) {
286                         
287                         final SpellProblem problem= new SpellProblem(event.getWord());
288                         
289                         problem.setSourceStart(event.getBegin());
290                         problem.setSourceEnd(event.getEnd());
291                         problem.setSentenceStart(event.isStart());
292                         problem.setDictionaryMatch(event.isMatch());
293                         
294                         try {
295                                 problem.setSourceLineNumber(fDocument.getLineOfOffset(event.getBegin()) + 1);
296                         } catch (BadLocationException x) {
297                                 // Do nothing
298                         }
299                         
300                         fRequestor.acceptProblem(problem);
301                 }
302         }
303
304         /*
305          * @see org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension#initialReconcile()
306          */
307         public void initialReconcile() {
308         }
309
310         /*
311          * @see org.eclipse.jface.text.reconciler.IReconcilingStrategy#reconcile(org.eclipse.jface.text.reconciler.DirtyRegion,org.eclipse.jface.text.IRegion)
312          */
313         public void reconcile(final DirtyRegion dirtyRegion, final IRegion subRegion) {
314                 reconcile(subRegion);
315         }
316
317         /*
318          * @see org.eclipse.jface.text.reconciler.IReconcilingStrategy#reconcile(org.eclipse.jface.text.IRegion)
319          */
320         public void reconcile(final IRegion region) {
321
322                 if (fPreferences.getBoolean(ISpellCheckPreferenceKeys.SPELLING_CHECK_SPELLING) && fRequestor != null) {
323
324                         try {
325
326                                 fRequestor.beginReporting();
327
328                                 ITypedRegion partition= null;
329                                 final ITypedRegion[] partitions= TextUtilities.computePartitioning(fDocument, fPartitioning, 0, fDocument.getLength(), false);
330
331                                 final Locale locale= getLocale();
332                                 final ISpellCheckEngine engine= SpellCheckEngine.getInstance();
333
334                                 final ISpellChecker checker= engine.createSpellChecker(locale, fPreferences);
335                                 if (checker != null) {
336                                         try {
337                                                 checker.addListener(this);
338                                                 
339                                                 for (int index= 0; index < partitions.length; index++) {
340                                                         partition= partitions[index];
341                                                         if (!partition.getType().equals(IDocument.DEFAULT_CONTENT_TYPE))
342                                                                 checker.execute(new SpellCheckIterator(fDocument, partition, locale));
343                                                 }
344                                                 
345                                         } finally {
346                                                 checker.removeListener(this);
347                                         }
348                                 }
349                         } catch (BadLocationException exception) {
350                                 // Do nothing
351                         } finally {
352                                 fRequestor.endReporting();
353                         }
354                 }
355         }
356
357         /*
358          * @see org.eclipse.jface.text.reconciler.IReconcilingStrategy#setDocument(org.eclipse.jface.text.IDocument)
359          */
360         public final void setDocument(final IDocument document) {
361                 fDocument= document;
362                 
363                 updateProblemRequestor();
364         }
365
366         /*
367          * @see org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension#setProgressMonitor(org.eclipse.core.runtime.IProgressMonitor)
368          */
369         public final void setProgressMonitor(final IProgressMonitor monitor) {
370                 // Do nothing
371         }
372
373         /**
374          * Update the problem requestor based on the current editor
375          * 
376          * @since 3.0
377          */
378         private void updateProblemRequestor() {
379                 final IAnnotationModel model= fEditor.getDocumentProvider().getAnnotationModel(fEditor.getEditorInput());
380                 fRequestor= (model instanceof IProblemRequestor) ? (IProblemRequestor) model : null;
381         }
382 }