001: /*******************************************************************************
002: * Copyright (c) 2006, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.texteditor.spelling;
011:
012: import java.util.ArrayList;
013: import java.util.HashMap;
014: import java.util.Iterator;
015: import java.util.List;
016: import java.util.Map;
017:
018: import org.eclipse.core.runtime.Assert;
019: import org.eclipse.core.runtime.IProgressMonitor;
020: import org.eclipse.core.runtime.Platform;
021: import org.eclipse.core.runtime.content.IContentType;
022: import org.eclipse.core.runtime.content.IContentTypeManager;
023:
024: import org.eclipse.jface.text.IDocument;
025: import org.eclipse.jface.text.IRegion;
026: import org.eclipse.jface.text.ISynchronizable;
027: import org.eclipse.jface.text.Position;
028: import org.eclipse.jface.text.Region;
029: import org.eclipse.jface.text.reconciler.DirtyRegion;
030: import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
031: import org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension;
032: import org.eclipse.jface.text.source.Annotation;
033: import org.eclipse.jface.text.source.IAnnotationModel;
034: import org.eclipse.jface.text.source.IAnnotationModelExtension;
035: import org.eclipse.jface.text.source.ISourceViewer;
036:
037: /**
038: * Reconcile strategy used for spell checking.
039: *
040: * @since 3.3
041: */
042: public class SpellingReconcileStrategy implements IReconcilingStrategy,
043: IReconcilingStrategyExtension {
044:
045: /**
046: * Spelling problem collector.
047: */
048: private class SpellingProblemCollector implements
049: ISpellingProblemCollector {
050:
051: /** Annotation model. */
052: private IAnnotationModel fAnnotationModel;
053:
054: /** Annotations to add. */
055: private Map fAddAnnotations;
056:
057: /** Lock object for modifying the annotations. */
058: private Object fLockObject;
059:
060: /**
061: * Initializes this collector with the given annotation model.
062: *
063: * @param annotationModel the annotation model
064: */
065: public SpellingProblemCollector(IAnnotationModel annotationModel) {
066: Assert.isLegal(annotationModel != null);
067: fAnnotationModel = annotationModel;
068: if (fAnnotationModel instanceof ISynchronizable)
069: fLockObject = ((ISynchronizable) fAnnotationModel)
070: .getLockObject();
071: else
072: fLockObject = fAnnotationModel;
073: }
074:
075: /*
076: * @see org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#accept(org.eclipse.ui.texteditor.spelling.SpellingProblem)
077: */
078: public void accept(SpellingProblem problem) {
079: fAddAnnotations.put(new SpellingAnnotation(problem),
080: new Position(problem.getOffset(), problem
081: .getLength()));
082: }
083:
084: /*
085: * @see org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#beginCollecting()
086: */
087: public void beginCollecting() {
088: fAddAnnotations = new HashMap();
089: }
090:
091: /*
092: * @see org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#endCollecting()
093: */
094: public void endCollecting() {
095:
096: List toRemove = new ArrayList();
097:
098: synchronized (fLockObject) {
099: Iterator iter = fAnnotationModel
100: .getAnnotationIterator();
101: while (iter.hasNext()) {
102: Annotation annotation = (Annotation) iter.next();
103: if (SpellingAnnotation.TYPE.equals(annotation
104: .getType()))
105: toRemove.add(annotation);
106: }
107: Annotation[] annotationsToRemove = (Annotation[]) toRemove
108: .toArray(new Annotation[toRemove.size()]);
109:
110: if (fAnnotationModel instanceof IAnnotationModelExtension)
111: ((IAnnotationModelExtension) fAnnotationModel)
112: .replaceAnnotations(annotationsToRemove,
113: fAddAnnotations);
114: else {
115: for (int i = 0; i < annotationsToRemove.length; i++)
116: fAnnotationModel
117: .removeAnnotation(annotationsToRemove[i]);
118: for (iter = fAddAnnotations.keySet().iterator(); iter
119: .hasNext();) {
120: Annotation annotation = (Annotation) iter
121: .next();
122: fAnnotationModel.addAnnotation(annotation,
123: (Position) fAddAnnotations
124: .get(annotation));
125: }
126: }
127: }
128:
129: fAddAnnotations = null;
130: }
131: }
132:
133: /** Text content type */
134: private static final IContentType TEXT_CONTENT_TYPE = Platform
135: .getContentTypeManager().getContentType(
136: IContentTypeManager.CT_TEXT);
137:
138: /** The text editor to operate on. */
139: private ISourceViewer fViewer;
140:
141: /** The document to operate on. */
142: private IDocument fDocument;
143:
144: /** The progress monitor. */
145: private IProgressMonitor fProgressMonitor;
146:
147: private SpellingService fSpellingService;
148:
149: private ISpellingProblemCollector fSpellingProblemCollector;
150:
151: /** The spelling context containing the Java source content type. */
152: private SpellingContext fSpellingContext;
153:
154: /**
155: * Creates a new comment reconcile strategy.
156: *
157: * @param viewer the source viewer
158: * @param spellingService the spelling service to use
159: */
160: public SpellingReconcileStrategy(ISourceViewer viewer,
161: SpellingService spellingService) {
162: Assert.isNotNull(viewer);
163: Assert.isNotNull(spellingService);
164: fViewer = viewer;
165: fSpellingService = spellingService;
166: fSpellingContext = new SpellingContext();
167: fSpellingContext.setContentType(getContentType());
168:
169: }
170:
171: /*
172: * @see org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension#initialReconcile()
173: */
174: public void initialReconcile() {
175: reconcile(new Region(0, fDocument.getLength()));
176: }
177:
178: /*
179: * @see org.eclipse.jface.text.reconciler.IReconcilingStrategy#reconcile(org.eclipse.jface.text.reconciler.DirtyRegion,org.eclipse.jface.text.IRegion)
180: */
181: public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
182: reconcile(subRegion);
183: }
184:
185: /*
186: * @see org.eclipse.jface.text.reconciler.IReconcilingStrategy#reconcile(org.eclipse.jface.text.IRegion)
187: */
188: public void reconcile(IRegion region) {
189: if (getAnnotationModel() == null
190: || fSpellingProblemCollector == null)
191: return;
192:
193: fSpellingService.check(fDocument, fSpellingContext,
194: fSpellingProblemCollector, fProgressMonitor);
195: }
196:
197: /**
198: * Returns the content type of the underlying editor input.
199: *
200: * @return the content type of the underlying editor input or
201: * <code>null</code> if none could be determined
202: */
203: protected IContentType getContentType() {
204: return TEXT_CONTENT_TYPE;
205: }
206:
207: /**
208: * Returns the document which is spell checked.
209: *
210: * @return the document
211: */
212: protected final IDocument getDocument() {
213: return fDocument;
214: }
215:
216: /*
217: * @see org.eclipse.jface.text.reconciler.IReconcilingStrategy#setDocument(org.eclipse.jface.text.IDocument)
218: */
219: public void setDocument(IDocument document) {
220: fDocument = document;
221: fSpellingProblemCollector = createSpellingProblemCollector();
222: }
223:
224: /**
225: * Creates a new spelling problem collector.
226: *
227: * @return the collector or <code>null</code> if none is available
228: */
229: protected ISpellingProblemCollector createSpellingProblemCollector() {
230: IAnnotationModel model = getAnnotationModel();
231: if (model == null)
232: return null;
233: return new SpellingProblemCollector(model);
234: }
235:
236: /*
237: * @see org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension#setProgressMonitor(org.eclipse.core.runtime.IProgressMonitor)
238: */
239: public final void setProgressMonitor(IProgressMonitor monitor) {
240: fProgressMonitor = monitor;
241: }
242:
243: /**
244: * Returns the annotation model to be used by this reconcile strategy.
245: *
246: * @return the annotation model of the underlying editor input or
247: * <code>null</code> if none could be determined
248: */
249: protected IAnnotationModel getAnnotationModel() {
250: return fViewer.getAnnotationModel();
251: }
252:
253: }
|