/* ****************************************************************************** * Copyright (c) 2006-2012 XMind Ltd. and others. * * This file is a part of XMind 3. XMind releases 3 and * above are dual-licensed under the Eclipse Public License (EPL), * which is available at http://www.eclipse.org/legal/epl-v10.html * and the GNU Lesser General Public License (LGPL), * which is available at http://www.gnu.org/licenses/lgpl.html * See http://www.xmind.net/license.html for details. * * Contributors: * XMind Ltd. - initial API and implementation *******************************************************************************/ package org.xmind.ui.internal.spelling; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.osgi.service.datalocation.Location; import org.osgi.framework.Bundle; import com.swabunga.spell.engine.Configuration; import com.swabunga.spell.engine.SpellDictionary; import com.swabunga.spell.engine.SpellDictionaryHashMap; import com.swabunga.spell.event.SpellChecker; public class SpellCheckerAgent { private static final SpellCheckerAgent instance = new SpellCheckerAgent(); private SpellChecker spellChecker; private Configuration configuration; private List<ISpellCheckerVisitor> listeners = new ArrayList<ISpellCheckerVisitor>(); public static void resetSpellChecker() { getInstance().spellChecker = null; } public static void visitSpellChecker(ISpellCheckerVisitor visitor) { getInstance().doVisitSpellChecker(visitor); } public static void setConfigurations(IPreferenceStore prefStore) { getInstance().doSetConfigurations(prefStore); } public static void migrateUserDictFile() { getInstance().doMigrateUserDictFile(); } public static void addListener(ISpellCheckerVisitor listener) { getInstance().listeners.add(listener); } public static void removeListener(ISpellCheckerVisitor listener) { getInstance().listeners.remove(listener); } private synchronized void doVisitSpellChecker( final ISpellCheckerVisitor visitor) { if (spellChecker != null) { visitor.handleWith(spellChecker); return; } new Job(Messages.loadingSpellChecker) { protected IStatus run(IProgressMonitor monitor) { return loadSpellChecker(monitor, visitor); } }.schedule(); } public static void updateSpellChecker() { getInstance().doUpdateSpellChecker(); } private synchronized void doUpdateSpellChecker() { new Job(Messages.loadingSpellChecker) { protected IStatus run(IProgressMonitor monitor) { return loadSpellChecker(monitor, null); } }.schedule(); } private IStatus loadSpellChecker(IProgressMonitor monitor, ISpellCheckerVisitor visitor) { monitor.beginTask(null, 4); monitor.subTask(Messages.creatingSpellCheckerInstance); SpellChecker spellChecker = new SpellChecker(); monitor.worked(1); // Load system dictionaries monitor.subTask(Messages.addingSystemDictionary); addSystemDictionaries(spellChecker); monitor.worked(1); // Load user dictionaries and words monitor.subTask(Messages.addingUserDictionary); addUserDictionaries(spellChecker); monitor.worked(1); // Load configurations monitor.subTask(Messages.initializingSpellingSettings); setConfigurations(spellChecker); monitor.worked(1); this.spellChecker = spellChecker; monitor.subTask(Messages.notifyingSpellingVisitors); notifyVisitor(visitor); notifyListeners(); monitor.done(); return new Status(IStatus.OK, SpellingPlugin.PLUGIN_ID, "Finish loading spell checker"); //$NON-NLS-1$ } private void notifyVisitor(ISpellCheckerVisitor visitor) { if (visitor != null) { visitor.handleWith(spellChecker); } } private void notifyListeners() { if (listeners != null) { for (ISpellCheckerVisitor listener : listeners) { if (listener != null) { listener.handleWith(spellChecker); } } } } private void setConfigurations(SpellChecker spellChecker) { configuration = spellChecker.getConfiguration(); doSetConfigurations(SpellingPlugin.getDefault().getPreferenceStore()); } private void addUserDictionaries(SpellChecker spellChecker) { for (ISpellCheckerDescriptor descriptor : SpellCheckerRegistry .getInstance().getDescriptors()) { try { if (descriptor.isEnabled()) { spellChecker.addDictionary( new SpellDictionaryHashMap(new InputStreamReader( descriptor.openStream(), "utf-16le"))); //$NON-NLS-1$ } } catch (IOException e) { SpellingPlugin.log(e); } } // File userDict = FileUtils.ensureFileParent(new File(Core.getWorkspace() // .getAbsolutePath("spelling/user.dict"))); //$NON-NLS-1$ File userDictFile = getUserDictFile(); if (!userDictFile.exists()) { if (userDictFile.getParentFile() != null) { userDictFile.getParentFile().mkdirs(); } try { new FileOutputStream(userDictFile).close(); } catch (IOException ignore) { } } try { spellChecker.setUserDictionary( new SpellDictionaryHashMap(userDictFile)); } catch (IOException e) { SpellingPlugin.log(e); } } private void addSystemDictionaries(SpellChecker spellChecker) { if ((!SpellingPlugin.getDefault().getPreferenceStore() .getBoolean(SpellingPlugin.DEFAULT_SPELLING_CHECKER_INVISIBLE)) && (!SpellingPlugin.getDefault().getPreferenceStore() .getBoolean( SpellingPlugin.DEFAULT_SPELLING_CHECKER_DISABLED))) { loadDictionariesFromBundle(spellChecker, "net.sourceforge.jazzy", //$NON-NLS-1$ "dict/"); //$NON-NLS-1$ } loadDictionariesFromBundle(spellChecker, SpellingPlugin.PLUGIN_ID, "dict/"); //$NON-NLS-1$ } private void loadDictionariesFromBundle(SpellChecker spellChecker, String pluginId, String dirPath) { Bundle bundle = Platform.getBundle(pluginId); if (bundle != null) { Enumeration<String> dicts = bundle.getEntryPaths(dirPath); while (dicts.hasMoreElements()) { String path = dicts.nextElement(); if (path.endsWith(".dic") || path.endsWith(".dict")) { //$NON-NLS-1$ //$NON-NLS-2$ URL uri = bundle.getEntry(path); if (uri != null) { try { loadDictionaryFromURL(spellChecker, uri); } catch (IOException e) { SpellingPlugin.log(e, "Failed to load dictionary from platform://" //$NON-NLS-1$ + bundle.getSymbolicName() + "/" //$NON-NLS-1$ + path); } } } else if (path.endsWith("/")) { //$NON-NLS-1$ loadDictionariesFromBundle(spellChecker, pluginId, path); } } } } private void loadDictionaryFromURL(SpellChecker spellChecker, URL uri) throws IOException { InputStream dictStream = uri.openStream(); try { InputStreamReader dictReader = new InputStreamReader(dictStream, "utf-8"); //$NON-NLS-1$ try { SpellDictionary dict = new SpellDictionaryHashMap(dictReader); spellChecker.addDictionary(dict); } finally { dictReader.close(); } } finally { dictStream.close(); } } private void doSetConfigurations(IPreferenceStore ps) { if (configuration == null) return; configuration.setBoolean(Configuration.SPELL_IGNOREDIGITWORDS, ps.getBoolean(Configuration.SPELL_IGNOREDIGITWORDS)); configuration.setBoolean(Configuration.SPELL_IGNOREINTERNETADDRESSES, ps.getBoolean(Configuration.SPELL_IGNOREINTERNETADDRESSES)); configuration.setBoolean(Configuration.SPELL_IGNOREMIXEDCASE, ps.getBoolean(Configuration.SPELL_IGNOREMIXEDCASE)); configuration.setBoolean( Configuration.SPELL_IGNORESENTENCECAPITALIZATION, ps.getBoolean( Configuration.SPELL_IGNORESENTENCECAPITALIZATION)); configuration.setBoolean(Configuration.SPELL_IGNOREUPPERCASE, ps.getBoolean(Configuration.SPELL_IGNOREUPPERCASE)); } private void doMigrateUserDictFile() { File newFile = getUserDictFile(); if (newFile.exists()) return; Location instanceLocation = Platform.getInstanceLocation(); if (instanceLocation == null) return; URL instanceURL = instanceLocation.getURL(); if (instanceURL == null) return; try { instanceURL = FileLocator.toFileURL(instanceURL); } catch (IOException e) { } File instanceDir = new File(instanceURL.getFile()); if (!instanceDir.exists()) return; File oldFile = new File(new File(instanceDir, ".xmind"), //$NON-NLS-1$ "spelling/user.dict"); //$NON-NLS-1$ if (oldFile.exists()) { moveUserDictFile(oldFile, newFile); return; } oldFile = new File(instanceDir, "spelling/user.dict"); //$NON-NLS-1$ if (oldFile.exists()) { moveUserDictFile(oldFile, newFile); return; } } private static void moveUserDictFile(File oldFile, File newFile) { if (newFile.getParentFile() != null) { newFile.getParentFile().mkdirs(); } boolean moved = oldFile.renameTo(newFile); if (!moved) { SpellingPlugin.getDefault().getLog() .log(new Status(IStatus.WARNING, SpellingPlugin.PLUGIN_ID, "Failed to migrate old user dict file: " //$NON-NLS-1$ + oldFile.getAbsolutePath())); } } private static File getUserDictFile() { return new File(SpellingPlugin.getBundleDataPath("user.dict")); //$NON-NLS-1$ } private static SpellCheckerAgent getInstance() { return instance; } }