/*******************************************************************************
* Copyright (c) 2000, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.rubypeople.rdt.internal.ui.text.spelling;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.reconciler.DirtyRegion;
import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
import org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector;
import org.eclipse.ui.texteditor.spelling.SpellingContext;
import org.eclipse.ui.texteditor.spelling.SpellingProblem;
import org.eclipse.ui.texteditor.spelling.SpellingService;
import org.rubypeople.rdt.core.IProblemRequestor;
import org.rubypeople.rdt.core.RubyCore;
import org.rubypeople.rdt.core.compiler.IProblem;
/**
* Reconcile strategy for spell checking comments.
*
* @since 1.0
*/
public class RubySpellingReconcileStrategy implements IReconcilingStrategy, IReconcilingStrategyExtension
{
/**
* Spelling problem collector that forwards {@link SpellingProblem}s as {@link IProblem}s to the
* {@link IProblemRequestor}.
*/
private class SpellingProblemCollector implements ISpellingProblemCollector
{
/*
* @seeorg.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#accept(org.eclipse.ui.texteditor.spelling.
* SpellingProblem)
*/
public void accept(SpellingProblem problem)
{
IProblemRequestor requestor = fRequestor;
if (requestor != null)
{
try
{
int line = fDocument.getLineOfOffset(problem.getOffset()) + 1;
String word = fDocument.get(problem.getOffset(), problem.getLength());
boolean dictionaryMatch = false;
boolean sentenceStart = false;
if (problem instanceof RubySpellingProblem)
{
dictionaryMatch = ((RubySpellingProblem) problem).isDictionaryMatch();
sentenceStart = ((RubySpellingProblem) problem).isSentenceStart();
}
// see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=81514
IEditorInput editorInput = fEditor.getEditorInput();
if (editorInput != null)
{
CoreSpellingProblem iProblem = new CoreSpellingProblem(problem.getOffset(), problem.getOffset()
+ problem.getLength() - 1, line, problem.getMessage(), word, dictionaryMatch,
sentenceStart, fDocument, editorInput.getName());
requestor.acceptProblem(iProblem);
}
}
catch (BadLocationException x)
{
// drop this SpellingProblem
}
}
}
/*
* @see org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#beginCollecting()
*/
public void beginCollecting()
{
if (fRequestor != null)
fRequestor.beginReporting();
}
/*
* @see org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#endCollecting()
*/
public void endCollecting()
{
if (fRequestor != null)
fRequestor.endReporting();
}
}
/** The id of the problem */
public static final int SPELLING_PROBLEM_ID = 0x80000000;
/** The text editor to operate on. */
private ITextEditor fEditor;
/** The document to operate on. */
private IDocument fDocument;
/** The progress monitor. */
private IProgressMonitor fProgressMonitor;
/** The problem requester. */
private IProblemRequestor fRequestor;
/** The spelling problem collector. */
private ISpellingProblemCollector fCollector;
/**
* The spelling context containing the Ruby source content type.
* <p>
* Since his reconcile strategy is for the Compilation Unit editor which normally edits Ruby source files we always
* use the Ruby properties file content type for performance reasons.
* </p>
*
* @since 3.2
*/
private SpellingContext fSpellingContext;
/**
* Creates a new comment reconcile strategy.
*
* @param editor
* the text editor to operate on
*/
public RubySpellingReconcileStrategy(ITextEditor editor)
{
fEditor = editor;
fCollector = new SpellingProblemCollector();
fSpellingContext = new SpellingContext();
fSpellingContext.setContentType(Platform.getContentTypeManager().getContentType(
RubyCore.RUBY_SOURCE_CONTENT_TYPE));
updateProblemRequester();
}
/*
* @see org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension#initialReconcile()
*/
public void initialReconcile()
{
reconcile(new Region(0, fDocument.getLength()));
}
/*
* @see
* org.eclipse.jface.text.reconciler.IReconcilingStrategy#reconcile(org.eclipse.jface.text.reconciler.DirtyRegion
* ,org.eclipse.jface.text.IRegion)
*/
public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion)
{
reconcile(subRegion);
}
/*
* @see org.eclipse.jface.text.reconciler.IReconcilingStrategy#reconcile(org.eclipse.jface.text.IRegion)
*/
public void reconcile(IRegion region)
{
if (fRequestor != null && isSpellingEnabled())
{
// Force the ruby spelling engine first! then revert back?
boolean force = false;
Display display = null;
final String currentEngine = EditorsUI.getPreferenceStore().getString(
SpellingService.PREFERENCE_SPELLING_ENGINE);
if (currentEngine == null
|| !currentEngine.equals("org.rubypeople.rdt.internal.ui.text.spelling.DefaultSpellingEngine"))
{
force = true;
display = Display.getCurrent();
if (display == null)
{
display = Display.getDefault();
}
display.syncExec(new Runnable()
{
public void run()
{
EditorsUI.getPreferenceStore().setValue(SpellingService.PREFERENCE_SPELLING_ENGINE,
"org.rubypeople.rdt.internal.ui.text.spelling.DefaultSpellingEngine");
}
});
}
EditorsUI.getSpellingService().check(fDocument, fSpellingContext, fCollector, fProgressMonitor);
if (force)
{
display.syncExec(new Runnable()
{
public void run()
{
EditorsUI.getPreferenceStore().setValue(SpellingService.PREFERENCE_SPELLING_ENGINE,
currentEngine);
}
});
}
}
}
private boolean isSpellingEnabled()
{
return EditorsUI.getPreferenceStore().getBoolean(SpellingService.PREFERENCE_SPELLING_ENABLED);
}
/*
* @see org.eclipse.jface.text.reconciler.IReconcilingStrategy#setDocument(org.eclipse.jface.text.IDocument)
*/
public void setDocument(IDocument document)
{
fDocument = document;
updateProblemRequester();
}
/*
* @seeorg.eclipse.jface.text.reconciler.IReconcilingStrategyExtension#setProgressMonitor(org.eclipse.core.runtime.
* IProgressMonitor)
*/
public void setProgressMonitor(IProgressMonitor monitor)
{
fProgressMonitor = monitor;
}
/**
* Update the problem requester based on the current editor
*/
private void updateProblemRequester()
{
IAnnotationModel model = fEditor.getDocumentProvider().getAnnotationModel(fEditor.getEditorInput());
fRequestor = (model instanceof IProblemRequestor) ? (IProblemRequestor) model : null;
}
}