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