org.xmind.ui.internal.spelling.SpellingCheckPrefPage.java Source code

Java tutorial

Introduction

Here is the source code for org.xmind.ui.internal.spelling.SpellingCheckPrefPage.java

Source

/* ******************************************************************************
 * 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.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.FieldEditor;
import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.resource.ResourceManager;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.events.IHyperlinkListener;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.xmind.ui.browser.BrowserSupport;
import org.xmind.ui.browser.IBrowser;
import org.xmind.ui.browser.IBrowserSupport;
import org.xmind.ui.resources.ColorUtils;
import org.xmind.ui.viewers.CheckListViewer;

import com.swabunga.spell.engine.Configuration;

public class SpellingCheckPrefPage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {

    private static final String SPELLING_HELP_URL = "https://xmind.desk.com/customer/portal/articles/690243"; //$NON-NLS-1$

    private static final Object DEFAULT_PLACEHOLDER = Messages.defaultDictionary;

    private static class Element {

        private String name;

        private boolean enabled;

        private ISpellCheckerDescriptor descriptor;

        private String path;

        public Element(String name, boolean enabled, ISpellCheckerDescriptor descriptor, String path) {
            this.name = name;
            this.enabled = enabled;
            this.descriptor = descriptor;
            this.path = path;
        }

        public String getName() {
            return name;
        }

        public boolean isEnabled() {
            return enabled;
        }

        public ISpellCheckerDescriptor getDescriptor() {
            return descriptor;
        }

        public void setDescriptor(ISpellCheckerDescriptor descriptor) {
            this.descriptor = descriptor;
        }

        public String getPath() {
            return path;
        }

        public void setPath(String path) {
            this.path = path;
        }

    }

    private static class DictionaryLabelProvider extends LabelProvider {

        /*
         * (non-Javadoc)
         * @see
         * org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object)
         */
        @Override
        public String getText(Object element) {
            if (element instanceof Element)
                return ((Element) element).getName();
            return super.getText(element);
        }
    }

    private static class DictionaryComparator extends ViewerComparator {

        /**
         * 
         */
        public DictionaryComparator() {
            super(new Comparator<String>() {
                public int compare(String n1, String n2) {
                    // Compare no-extension name:
                    int s1 = n1.lastIndexOf('.');
                    int s2 = n2.lastIndexOf('.');
                    String p1 = s1 < 0 ? n1 : n1.substring(0, s1);
                    String p2 = s2 < 0 ? n2 : n2.substring(0, s2);
                    int c = p1.compareTo(p2);
                    if (c != 0)
                        return c;

                    // Compare full name:
                    return n1.compareTo(n2);
                }
            });
        }

        /*
         * (non-Javadoc)
         * @see
         * org.eclipse.jface.viewers.ViewerComparator#category(java.lang.Object)
         */
        @Override
        public int category(Object element) {
            if (element == DEFAULT_PLACEHOLDER)
                return 0;
            return 1;
        }
    }

    private class DictionarySelectionListener implements ISelectionChangedListener {

        /*
         * (non-Javadoc)
         * @see
         * org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged
         * (org.eclipse.jface.viewers.SelectionChangedEvent)
         */
        public void selectionChanged(SelectionChangedEvent event) {
            updateDictionaryControls();
        }

    }

    private class DictionaryOpenHandler implements IOpenListener {
        public void open(OpenEvent event) {
            selectSingleDictionary(event.getSelection());
        }
    }

    private List<FieldEditor> settingFields = new ArrayList<FieldEditor>();

    private Composite settingsParent;

    private ResourceManager resources;

    private CheckListViewer dictionaryViewer;

    private Button addButton;

    private Button removeButton;

    private List<Element> addElementReferences = new ArrayList<Element>();

    private List<ISpellCheckerDescriptor> removeDescriptorReferences = new ArrayList<ISpellCheckerDescriptor>();

    public SpellingCheckPrefPage() {
        super(Messages.SpellingPrefPage_title, FLAT);
    }

    public void init(IWorkbench workbench) {
        setPreferenceStore(SpellingPlugin.getDefault().getPreferenceStore());
    }

    protected void createFieldEditors() {
        addField(new BooleanFieldEditor(SpellingPlugin.SPELLING_CHECK_ENABLED, Messages.enableSpellCheck,
                getFieldEditorParent()));
        addSpellingSettings(getFieldEditorParent());
        addDictionariesPanel(getFieldEditorParent());

        updateOptions(SpellingPlugin.isSpellingCheckEnabled());
        updateDictionaryControls();
    }

    private void addSpellingSettings(Composite composite) {
        resources = new LocalResourceManager(JFaceResources.getResources(), composite);

        settingsParent = createSettingsParent(composite);
        addSettingField(Configuration.SPELL_IGNOREUPPERCASE, Messages.ignoreAllCapital);
        addSettingField(Configuration.SPELL_IGNOREMIXEDCASE, Messages.ignoreMultiCapital);
        addSettingField(Configuration.SPELL_IGNOREINTERNETADDRESSES, Messages.ignoreWebAddress);
        addSettingField(Configuration.SPELL_IGNOREDIGITWORDS, Messages.ignoreNumberousAppendix);
        addSettingField(Configuration.SPELL_IGNORESENTENCECAPITALIZATION, Messages.ignoreFirstLowercaseSentences);
    }

    private void addSettingField(String name, String label) {
        FieldEditor field = new BooleanFieldEditor(name, label, settingsParent);
        addField(field);
        settingFields.add(field);
    }

    private Composite createSettingsParent(Composite parent) {
        GridLayout layout = new GridLayout(1, false);
        layout.marginTop = 7;
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        layout.verticalSpacing = 0;
        layout.horizontalSpacing = 0;
        parent.setLayout(layout);

        Group group = new Group(parent, SWT.NONE);
        group.setText(Messages.options);
        group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        GridLayout groupLayout = new GridLayout(1, false);
        groupLayout.marginWidth = 5;
        groupLayout.marginHeight = 5;
        groupLayout.verticalSpacing = 5;
        groupLayout.horizontalSpacing = 0;
        group.setLayout(groupLayout);

        return group;
    }

    private void updateOptions(boolean enabled) {
        settingsParent.setEnabled(enabled);
        for (FieldEditor field : settingFields) {
            field.setEnabled(enabled, settingsParent);
        }
    }

    private void addDictionariesPanel(Composite parent) {
        GridLayout layout = new GridLayout(1, false);
        layout.marginTop = 7;
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        layout.verticalSpacing = 0;
        layout.horizontalSpacing = 0;
        parent.setLayout(layout);
        parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

        Group group = new Group(parent, SWT.NONE);
        group.setText(Messages.dictionaries);
        group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        GridLayout groupLayout = new GridLayout(2, false);
        groupLayout.marginWidth = 5;
        groupLayout.marginHeight = 5;
        groupLayout.verticalSpacing = 5;
        groupLayout.horizontalSpacing = 5;
        group.setLayout(groupLayout);

        createDictionaryViewer(group);
        createDictionaryControls(group);
        createDetailsLink(group);
    }

    private void createDictionaryViewer(Composite parent) {
        dictionaryViewer = new CheckListViewer(parent, SWT.BORDER);
        dictionaryViewer.getControl().setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
        dictionaryViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

        dictionaryViewer.setContentProvider(new ArrayContentProvider());
        dictionaryViewer.setLabelProvider(new DictionaryLabelProvider());
        dictionaryViewer.setComparator(new DictionaryComparator());
        dictionaryViewer.addSelectionChangedListener(new DictionarySelectionListener());
        dictionaryViewer.addOpenListener(new DictionaryOpenHandler());

        dictionaryViewer.setInput(getInput());
        initCheckStates();
    }

    private Object getInput() {
        List<Object> objects = new ArrayList<Object>();

        if (!getPreferenceStore().getBoolean(SpellingPlugin.DEFAULT_SPELLING_CHECKER_INVISIBLE)) {
            objects.add(DEFAULT_PLACEHOLDER);
        }

        List<ISpellCheckerDescriptor> descriptors = SpellCheckerRegistry.getInstance().getDescriptors();
        for (ISpellCheckerDescriptor descriptor : descriptors) {
            String name = descriptor.getName();
            boolean enabled = descriptor.isEnabled();
            objects.add(new Element(name, enabled, descriptor, null));
        }

        return objects;
    }

    private void initCheckStates() {
        if (dictionaryViewer == null || dictionaryViewer.getControl() == null
                || dictionaryViewer.getControl().isDisposed()) {
            return;
        }

        Object[] elements = ((IStructuredContentProvider) dictionaryViewer.getContentProvider())
                .getElements(dictionaryViewer.getInput());
        for (Object element : elements) {
            boolean enabled = false;
            if (element instanceof Element) {
                enabled = ((Element) element).isEnabled();
            } else if (element == DEFAULT_PLACEHOLDER) {
                enabled = !getPreferenceStore().getBoolean(SpellingPlugin.DEFAULT_SPELLING_CHECKER_DISABLED);
            }

            dictionaryViewer.setChecked(element, enabled);
        }
    }

    private void createDictionaryControls(Composite parent) {
        Composite composite = new Composite(parent, SWT.NONE);
        composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));
        GridLayout layout = new GridLayout(1, true);
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        layout.verticalSpacing = 0;
        layout.horizontalSpacing = 0;
        composite.setLayout(layout);

        Composite buttonBar = new Composite(composite, SWT.NONE);
        buttonBar.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
        GridLayout buttonBarLayout = new GridLayout(1, true);
        buttonBarLayout.marginWidth = 0;
        buttonBarLayout.marginHeight = 0;
        buttonBarLayout.verticalSpacing = 10;
        buttonBarLayout.horizontalSpacing = 0;
        buttonBar.setLayout(buttonBarLayout);

        createAddDictionaryButton(buttonBar);
        createRemoveDictionaryButton(buttonBar);
        //createDictionaryInfoPanel(composite);
    }

    private void createDetailsLink(Composite parent) {
        Hyperlink hyperlink = new Hyperlink(parent, SWT.SINGLE);
        hyperlink.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
        ((GridData) hyperlink.getLayoutData()).horizontalSpan = 2;
        hyperlink.setText(Messages.detailsLink_text);
        hyperlink.setForeground((Color) resources.get(ColorUtils.toDescriptor("#006CF9"))); //$NON-NLS-1$
        hyperlink.addHyperlinkListener(new IHyperlinkListener() {
            public void linkExited(HyperlinkEvent e) {
            }

            public void linkEntered(HyperlinkEvent e) {
            }

            public void linkActivated(HyperlinkEvent e) {
                final IBrowser browser;
                browser = BrowserSupport.getInstance().createBrowser(IBrowserSupport.AS_EXTERNAL);
                SafeRunner.run(new SafeRunnable() {
                    public void run() throws Exception {
                        browser.openURL(SPELLING_HELP_URL);
                    }
                });
            }
        });
    }

    private void createAddDictionaryButton(Composite parent) {
        addButton = new Button(parent, SWT.PUSH);
        addButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
        addButton.setText(Messages.dictionaries_add);
        addButton.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event event) {
                addDictionaryReference();
            }
        });
    }

    private void createRemoveDictionaryButton(Composite parent) {
        removeButton = new Button(parent, SWT.PUSH);
        removeButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
        removeButton.setText(Messages.dictionaries_remove);
        removeButton.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event event) {
                removeSelectedDictionaryReference();
            }
        });
    }

    @SuppressWarnings("unchecked")
    private void addDictionaryReference() {
        FileDialog dialog = new FileDialog(getShell(), SWT.OPEN);
        dialog.setFilterExtensions(new String[] { "*.dic;*.dict;*.txt;*.*" }); //$NON-NLS-1$
        final String path = dialog.open();
        if (path == null)
            return;

        List<String> nameExclusions = new ArrayList<String>();
        if (dictionaryViewer.getInput() instanceof List<?>) {
            for (Object obj : (List<?>) dictionaryViewer.getInput()) {
                if (obj instanceof Element) {
                    nameExclusions.add(((Element) obj).getName());
                }
            }
        }

        String addedDictionaryName = SpellCheckerRegistry.getInstance().getImportableDictFileName(new File(path),
                nameExclusions);
        Element addedElement = new Element(addedDictionaryName, false, null, path);

        if (dictionaryViewer.getInput() instanceof List<?>) {
            ((List<Object>) dictionaryViewer.getInput()).add(addedElement);
        }

        if (!addElementReferences.contains(addedElement)) {
            addElementReferences.add(addedElement);
        }

        dictionaryViewer.refresh();
    }

    private void removeSelectedDictionaryReference() {
        Object selection = ((IStructuredSelection) dictionaryViewer.getSelection()).getFirstElement();
        if (selection == null)
            return;

        // Confirm remove
        String name = ((ILabelProvider) dictionaryViewer.getLabelProvider()).getText(selection);
        if (!MessageDialog.openConfirm(getShell(), Messages.dictionaries_remove_confirm_title,
                NLS.bind(Messages.dictionaries_remove_confirm_message, name)))
            return;

        removeDictionaryReference(selection);

        dictionaryViewer.refresh();
    }

    @SuppressWarnings("unchecked")
    private void removeDictionaryReference(Object obj) {
        if (dictionaryViewer.getInput() instanceof List<?>) {
            ((List<Object>) dictionaryViewer.getInput()).remove(obj);
        }

        if (obj instanceof Element) {
            Element element = (Element) obj;
            if (element.getDescriptor() != null) {
                //remove old element
                removeDescriptorReferences.add(element.getDescriptor());
            } else if (element.getPath() != null) {
                //remove new element
                addElementReferences.remove(element);
            }
        }
    }

    private void updateDictionaryControls() {
        ISelection selection = dictionaryViewer.getSelection();
        if (selection instanceof IStructuredSelection) {
            boolean containDefault = ((IStructuredSelection) selection).toList().contains(DEFAULT_PLACEHOLDER);
            removeButton.setEnabled(!dictionaryViewer.getSelection().isEmpty() && !containDefault);
        } else {
            removeButton.setEnabled(!dictionaryViewer.getSelection().isEmpty());
        }
    }

    //    /**
    //     * @param composite
    //     */
    //    private void createDictionaryInfoPanel(Composite composite) {
    //
    //    }

    public void propertyChange(PropertyChangeEvent event) {
        FieldEditor field = (FieldEditor) event.getSource();
        if (SpellingPlugin.SPELLING_CHECK_ENABLED.equals(field.getPreferenceName())) {
            updateOptions(((BooleanFieldEditor) field).getBooleanValue());
        }
        super.propertyChange(event);
    }

    public void selectSingleDictionary(ISelection selection) {
        if (dictionaryViewer == null || dictionaryViewer.getControl() == null
                || dictionaryViewer.getControl().isDisposed()) {
            return;
        }

        if (selection instanceof IStructuredSelection) {
            Object selectedElement = ((IStructuredSelection) selection).getFirstElement();

            //disabled other element
            Object[] checkedElements = dictionaryViewer.getCheckedElements();
            for (Object checkedElement : checkedElements) {
                if (selectedElement != checkedElement) {
                    dictionaryViewer.setChecked(checkedElement, false);
                }
            }

            //enabled selected element
            dictionaryViewer.setChecked(selectedElement, true);
        }
    }

    @Override
    public boolean performOk() {
        List<Object> oldEnabledDictionaries = getEnabledDictionaries();

        removeReferenceDictionarys();
        addReferenceDictionarys();

        //manage Default element
        getPreferenceStore().setValue(SpellingPlugin.DEFAULT_SPELLING_CHECKER_INVISIBLE,
                !((List<?>) dictionaryViewer.getInput()).contains(DEFAULT_PLACEHOLDER));

        for (int i = 0; i < dictionaryViewer.getItemCount(); i++) {
            Object element = dictionaryViewer.getElementAt(i);
            boolean enabled = dictionaryViewer.getChecked(element);

            if (element instanceof Element) {
                ((Element) element).getDescriptor().setEnabled(enabled);
            } else if (element == DEFAULT_PLACEHOLDER) {
                getPreferenceStore().setValue(SpellingPlugin.DEFAULT_SPELLING_CHECKER_DISABLED, !enabled);
            }
        }

        List<Object> newEnabledDictionaries = getEnabledDictionaries();
        boolean needUpdated = !oldEnabledDictionaries.equals(newEnabledDictionaries);
        if (needUpdated) {
            SpellCheckerAgent.updateSpellChecker();
        }

        return super.performOk();
    }

    private List<Object> getEnabledDictionaries() {
        List<Object> objects = new ArrayList<Object>();

        if (!getPreferenceStore().getBoolean(SpellingPlugin.DEFAULT_SPELLING_CHECKER_INVISIBLE)
                && !getPreferenceStore().getBoolean(SpellingPlugin.DEFAULT_SPELLING_CHECKER_DISABLED)) {
            objects.add(DEFAULT_PLACEHOLDER);
        }

        List<ISpellCheckerDescriptor> descriptors = SpellCheckerRegistry.getInstance().getDescriptors();
        for (ISpellCheckerDescriptor descriptor : descriptors) {
            if (descriptor.isEnabled()) {
                objects.add(descriptor);
            }
        }

        return objects;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void performDefaults() {
        if (!((List<?>) dictionaryViewer.getInput()).contains(DEFAULT_PLACEHOLDER)) {
            ((List<Object>) dictionaryViewer.getInput()).add(0, DEFAULT_PLACEHOLDER);
            dictionaryViewer.refresh();
        }

        for (int i = 0; i < dictionaryViewer.getItemCount(); i++) {
            Object element = dictionaryViewer.getElementAt(i);

            if (element instanceof Element) {
                removeDictionaryReference(element);
            } else if (element == DEFAULT_PLACEHOLDER) {
                dictionaryViewer.setChecked(element, true);
            }
        }
        super.performDefaults();

        dictionaryViewer.refresh();
    }

    private void addReferenceDictionarys() {
        for (Element element : addElementReferences) {
            addDictionary(element);
        }
        addElementReferences.clear();
    }

    private void removeReferenceDictionarys() {
        for (ISpellCheckerDescriptor descriptor : removeDescriptorReferences) {
            removeDictionary(descriptor);
        }
        removeDescriptorReferences.clear();
    }

    private void addDictionary(final Element element) {
        final String path = element.getPath();
        if (path == null)
            return;

        try {
            ProgressMonitorDialog progress = new ProgressMonitorDialog(getShell());
            progress.setOpenOnRun(false);
            progress.run(true, false, new IRunnableWithProgress() {
                public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                    monitor.beginTask(Messages.addingDictionary, 1);
                    SafeRunner.run(new SafeRunnable() {
                        public void run() throws Exception {
                            ISpellCheckerDescriptor descriptor = SpellCheckerRegistry.getInstance()
                                    .importDictFile(new File(path), element.getName());
                            element.setPath(null);
                            element.setDescriptor(descriptor);
                        }
                    });
                    monitor.done();
                }
            });
        } catch (InvocationTargetException e) {
        } catch (InterruptedException e) {
        }
    }

    private void removeDictionary(final ISpellCheckerDescriptor descriptor) {
        // Remove dictionary descriptor and local file
        try {
            ProgressMonitorDialog progress = new ProgressMonitorDialog(getShell());
            progress.setOpenOnRun(false);
            progress.run(true, false, new IRunnableWithProgress() {
                public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                    monitor.beginTask(Messages.removingDictionary, 1);
                    SafeRunner.run(new SafeRunnable() {
                        public void run() throws Exception {
                            SpellCheckerRegistry.getInstance().removeDictionary(descriptor);
                        }
                    });
                    monitor.done();
                }
            });
        } catch (InvocationTargetException e) {
        } catch (InterruptedException e) {
        }
    }

    @Override
    public void dispose() {
        if (addElementReferences != null) {
            addElementReferences.clear();
            addElementReferences = null;
        }
        if (removeDescriptorReferences != null) {
            removeDescriptorReferences.clear();
            removeDescriptorReferences = null;
        }

        super.dispose();
    }

}