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