/*******************************************************************************
* Copyright (c) 2000, 2005 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 java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.rubypeople.rdt.internal.ui.RubyPlugin;
import org.rubypeople.rdt.internal.ui.text.spelling.engine.DefaultSpellChecker;
import org.rubypeople.rdt.internal.ui.text.spelling.engine.ISpellCheckEngine;
import org.rubypeople.rdt.internal.ui.text.spelling.engine.ISpellCheckPreferenceKeys;
import org.rubypeople.rdt.internal.ui.text.spelling.engine.ISpellChecker;
import org.rubypeople.rdt.internal.ui.text.spelling.engine.ISpellDictionary;
import org.rubypeople.rdt.internal.ui.text.spelling.engine.PersistentSpellDictionary;
/**
* Spell check engine for Ruby source spell checking.
*
* @since 3.0
*/
public class SpellCheckEngine implements ISpellCheckEngine, IPropertyChangeListener
{
/** The dictionary location */
public static final String DICTIONARY_LOCATION = "dictionaries/"; //$NON-NLS-1$
/** The singleton engine instance */
private static ISpellCheckEngine fgEngine = null;
/**
* Returns the available locales for this spell check engine.
*
* @return The available locales for this engine
*/
public static Set<Locale> getAvailableLocales()
{
URL url = null;
Locale locale = null;
InputStream stream = null;
final Set<Locale> result = new HashSet<Locale>();
try
{
final URL location = getDictionaryLocation();
if (location == null)
return Collections.EMPTY_SET;
final Locale[] locales = Locale.getAvailableLocales();
for (int index = 0; index < locales.length; index++)
{
locale = locales[index];
url = new URL(location, locale.toString() + ".dictionary"); //$NON-NLS-1$
try
{
stream = url.openStream();
if (stream != null)
{
try
{
result.add(locale);
}
finally
{
stream.close();
}
}
}
catch (IOException exception)
{
// Do nothing
}
}
}
catch (MalformedURLException exception)
{
// Do nothing
}
return result;
}
/**
* Returns the default locale for this engine.
*
* @return The default locale
*/
public static Locale getDefaultLocale()
{
return Locale.getDefault();
}
/**
* Returns the dictionary location.
*
* @throws MalformedURLException
* if the URL could not be created
* @return The dictionary location, or <code>null</code> if the location is not known
*/
private static URL getDictionaryLocation() throws MalformedURLException
{
final Plugin plugin = RubyPlugin.getDefault();
if (plugin != null)
return plugin.getBundle().getEntry("/" + DICTIONARY_LOCATION); //$NON-NLS-1$
return null;
}
/**
* Returns the singleton instance of the spell check engine.
*
* @return The singleton instance of the spell check engine
*/
public static final synchronized ISpellCheckEngine getInstance()
{
if (fgEngine == null)
fgEngine = new SpellCheckEngine();
return fgEngine;
}
/** The registered locale insenitive dictionaries */
private final Set<ISpellDictionary> fGlobalDictionaries = new HashSet<ISpellDictionary>();
/** The current locale */
private Locale fLocale = null;
/** The spell checker for fLocale */
private ISpellChecker fChecker = null;
/** The registered locale sensitive dictionaries */
private final Map<Locale, ISpellDictionary> fLocaleDictionaries = new HashMap<Locale, ISpellDictionary>();
/** The preference store where to listen */
private IPreferenceStore fPreferences = null;
/** The user dictionary */
private ISpellDictionary fUserDictionary = null;
/**
* Creates a new spell check manager.
*/
private SpellCheckEngine()
{
fGlobalDictionaries.add(new TaskTagDictionary());
// fGlobalDictionaries.add(new HtmlTagDictionary());
// fGlobalDictionaries.add(new RDocTagDictionary());
try
{
Locale locale = null;
final URL location = getDictionaryLocation();
for (final Iterator<Locale> iterator = getAvailableLocales().iterator(); iterator.hasNext();)
{
locale = iterator.next();
fLocaleDictionaries.put(locale, new SpellReconcileDictionary(locale, location));
}
}
catch (MalformedURLException exception)
{
// Do nothing
}
}
/*
* @see
* org.eclipse.jdt.ui.text.spelling.engine.ISpellCheckEngine#createSpellChecker(java.util.Locale,org.eclipse.jface
* .preference.IPreferenceStore)
*/
public final synchronized ISpellChecker createSpellChecker(final Locale locale, final IPreferenceStore store)
{
if (fLocale != null && fLocale.equals(locale))
return fChecker;
if (fChecker == null)
{
fChecker = new DefaultSpellChecker(store);
store.addPropertyChangeListener(this);
fPreferences = store;
ISpellDictionary dictionary = null;
for (Iterator<ISpellDictionary> iterator = fGlobalDictionaries.iterator(); iterator.hasNext();)
{
dictionary = iterator.next();
fChecker.addDictionary(dictionary);
}
}
ISpellDictionary dictionary = null;
if (fLocale != null)
{
dictionary = (ISpellDictionary) fLocaleDictionaries.get(fLocale);
if (dictionary != null)
{
fChecker.removeDictionary(dictionary);
dictionary.unload();
}
}
fLocale = locale;
dictionary = (ISpellDictionary) fLocaleDictionaries.get(locale);
if (dictionary == null)
{
if (!getDefaultLocale().equals(locale))
{
if (fPreferences != null)
fPreferences.removePropertyChangeListener(this);
fChecker = null;
fLocale = null;
}
}
else
fChecker.addDictionary(dictionary);
if (fPreferences != null)
propertyChange(new PropertyChangeEvent(this, ISpellCheckPreferenceKeys.SPELLING_USER_DICTIONARY, null,
fPreferences.getString(ISpellCheckPreferenceKeys.SPELLING_USER_DICTIONARY)));
return fChecker;
}
/*
* @see org.eclipse.jdt.ui.text.spelling.engine.ISpellCheckEngine#getLocale()
*/
public final Locale getLocale()
{
return fLocale;
}
/*
* @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
*/
public final void propertyChange(final PropertyChangeEvent event)
{
if (fChecker != null && event.getProperty().equals(ISpellCheckPreferenceKeys.SPELLING_USER_DICTIONARY))
{
if (fUserDictionary != null)
{
fChecker.removeDictionary(fUserDictionary);
fUserDictionary = null;
}
final String file = (String) event.getNewValue();
if (file.length() > 0)
{
try
{
final URL url = new URL("file", null, file); //$NON-NLS-1$
InputStream stream = url.openStream();
if (stream != null)
{
try
{
fUserDictionary = new PersistentSpellDictionary(url);
fChecker.addDictionary(fUserDictionary);
}
finally
{
stream.close();
}
}
}
catch (MalformedURLException exception)
{
// Do nothing
}
catch (IOException exception)
{
// Do nothing
}
}
}
}
/*
* @see
* org.eclipse.jdt.ui.text.spelling.engine.ISpellCheckEngine#registerDictionary(org.eclipse.jdt.ui.text.spelling
* .engine.ISpellDictionary)
*/
public synchronized final void registerDictionary(final ISpellDictionary dictionary)
{
fGlobalDictionaries.add(dictionary);
if (fChecker != null)
fChecker.addDictionary(dictionary);
}
/*
* @see
* org.eclipse.jdt.ui.text.spelling.engine.ISpellCheckEngine#registerDictionary(java.util.Locale,org.eclipse.jdt
* .ui.text.spelling.engine.ISpellDictionary)
*/
public synchronized final void registerDictionary(final Locale locale, final ISpellDictionary dictionary)
{
fLocaleDictionaries.put(locale, dictionary);
if (fChecker != null && fLocale != null && fLocale.equals(locale))
fChecker.addDictionary(dictionary);
}
/*
* @see org.eclipse.jdt.ui.text.spelling.engine.ISpellCheckEngine#unload()
*/
public synchronized final void unload()
{
ISpellDictionary dictionary = null;
for (final Iterator<ISpellDictionary> iterator = fGlobalDictionaries.iterator(); iterator.hasNext();)
{
dictionary = iterator.next();
dictionary.unload();
}
for (final Iterator<ISpellDictionary> iterator = fLocaleDictionaries.values().iterator(); iterator.hasNext();)
{
dictionary = iterator.next();
dictionary.unload();
}
if (fPreferences != null)
fPreferences.removePropertyChangeListener(this);
fUserDictionary = null;
fChecker = null;
}
/*
* @see
* org.eclipse.jdt.ui.text.spelling.engine.ISpellCheckEngine#unregisterDictionary(org.eclipse.jdt.ui.text.spelling
* .engine.ISpellDictionary)
*/
public synchronized final void unregisterDictionary(final ISpellDictionary dictionary)
{
fGlobalDictionaries.remove(dictionary);
fLocaleDictionaries.values().remove(dictionary);
if (fChecker != null)
fChecker.removeDictionary(dictionary);
dictionary.unload();
}
}