View | Details | Raw Unified | Return to bug 185695
Collapse All | Expand All

(-)src/org/eclipse/jdt/text/tests/spelling/SpellCheckEngineTestCase.java (-6 / +8 lines)
Lines 22-35 Link Here
22
22
23
import org.eclipse.jface.preference.IPreferenceStore;
23
import org.eclipse.jface.preference.IPreferenceStore;
24
24
25
import org.eclipse.ui.internal.texteditor.spelling.engine.AbstractSpellDictionary;
26
import org.eclipse.ui.internal.texteditor.spelling.engine.DefaultPhoneticDistanceAlgorithm;
27
28
import org.eclipse.ui.texteditor.spelling.correction.RankedWordProposal;
29
import org.eclipse.ui.texteditor.spelling.engine.ISpellCheckEngine;
30
import org.eclipse.ui.texteditor.spelling.engine.ISpellChecker;
31
import org.eclipse.ui.texteditor.spelling.engine.SpellCheckEngine;
32
25
import org.eclipse.jdt.ui.PreferenceConstants;
33
import org.eclipse.jdt.ui.PreferenceConstants;
26
34
27
import org.eclipse.jdt.internal.ui.text.spelling.SpellCheckEngine;
28
import org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary;
29
import org.eclipse.jdt.internal.ui.text.spelling.engine.DefaultPhoneticDistanceAlgorithm;
30
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine;
31
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker;
32
import org.eclipse.jdt.internal.ui.text.spelling.engine.RankedWordProposal;
33
35
34
public class SpellCheckEngineTestCase extends TestCase {
36
public class SpellCheckEngineTestCase extends TestCase {
35
37
(-)META-INF/MANIFEST.MF (-4 / +3 lines)
Lines 42-48 Link Here
42
 org.eclipse.jdt.internal.corext.refactoring.util;x-internal:=true,
42
 org.eclipse.jdt.internal.corext.refactoring.util;x-internal:=true,
43
 org.eclipse.jdt.internal.corext.template.java;x-internal:=true,
43
 org.eclipse.jdt.internal.corext.template.java;x-internal:=true,
44
 org.eclipse.jdt.internal.corext.util;x-friends:="org.eclipse.jdt.junit",
44
 org.eclipse.jdt.internal.corext.util;x-friends:="org.eclipse.jdt.junit",
45
 org.eclipse.jdt.internal.ui;x-friends:="org.eclipse.jdt.junit, org.eclipse.jdt.apt.ui",
45
 org.eclipse.jdt.internal.ui;x-friends:="org.eclipse.jdt.junit,org.eclipse.jdt.apt.ui",
46
 org.eclipse.jdt.internal.ui.actions;x-friends:="org.eclipse.jdt.junit",
46
 org.eclipse.jdt.internal.ui.actions;x-friends:="org.eclipse.jdt.junit",
47
 org.eclipse.jdt.internal.ui.browsing;x-internal:=true,
47
 org.eclipse.jdt.internal.ui.browsing;x-internal:=true,
48
 org.eclipse.jdt.internal.ui.callhierarchy;x-internal:=true,
48
 org.eclipse.jdt.internal.ui.callhierarchy;x-internal:=true,
Lines 86-98 Link Here
86
 org.eclipse.jdt.internal.ui.text.java.hover;x-internal:=true,
86
 org.eclipse.jdt.internal.ui.text.java.hover;x-internal:=true,
87
 org.eclipse.jdt.internal.ui.text.javadoc;x-internal:=true,
87
 org.eclipse.jdt.internal.ui.text.javadoc;x-internal:=true,
88
 org.eclipse.jdt.internal.ui.text.spelling;x-internal:=true,
88
 org.eclipse.jdt.internal.ui.text.spelling;x-internal:=true,
89
 org.eclipse.jdt.internal.ui.text.spelling.engine;x-internal:=true,
90
 org.eclipse.jdt.internal.ui.text.template.contentassist;x-internal:=true,
89
 org.eclipse.jdt.internal.ui.text.template.contentassist;x-internal:=true,
91
 org.eclipse.jdt.internal.ui.text.template.preferences;x-internal:=true,
90
 org.eclipse.jdt.internal.ui.text.template.preferences;x-internal:=true,
92
 org.eclipse.jdt.internal.ui.typehierarchy;x-internal:=true,
91
 org.eclipse.jdt.internal.ui.typehierarchy;x-internal:=true,
93
 org.eclipse.jdt.internal.ui.util;x-friends:="org.eclipse.jdt.junit, org.eclipse.jdt.apt.ui",
92
 org.eclipse.jdt.internal.ui.util;x-friends:="org.eclipse.jdt.junit,org.eclipse.jdt.apt.ui",
94
 org.eclipse.jdt.internal.ui.viewsupport;x-friends:="org.eclipse.jdt.junit",
93
 org.eclipse.jdt.internal.ui.viewsupport;x-friends:="org.eclipse.jdt.junit",
95
 org.eclipse.jdt.internal.ui.wizards;x-friends:="org.eclipse.jdt.junit, org.eclipse.jdt.apt.ui",
94
 org.eclipse.jdt.internal.ui.wizards;x-friends:="org.eclipse.jdt.junit,org.eclipse.jdt.apt.ui",
96
 org.eclipse.jdt.internal.ui.wizards.buildpaths;x-internal:=true,
95
 org.eclipse.jdt.internal.ui.wizards.buildpaths;x-internal:=true,
97
 org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage;x-internal:=true,
96
 org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage;x-internal:=true,
98
 org.eclipse.jdt.internal.ui.wizards.dialogfields;x-friends:="org.eclipse.jdt.apt.ui",
97
 org.eclipse.jdt.internal.ui.wizards.dialogfields;x-friends:="org.eclipse.jdt.apt.ui",
(-)plugin.xml (-7 / +20 lines)
Lines 185-198 Link Here
185
            class="org.eclipse.jdt.internal.ui.text.correction.QuickFixProcessor"
185
            class="org.eclipse.jdt.internal.ui.text.correction.QuickFixProcessor"
186
            id="org.eclipse.jdt.ui.text.correction.QuickFixProcessor">
186
            id="org.eclipse.jdt.ui.text.correction.QuickFixProcessor">
187
      </quickFixProcessor>
187
      </quickFixProcessor>
188
      <quickFixProcessor
188
     <!-- how should spell problems be enabled in java editor (this is same problem as in properties file editor) 
189
     <quickFixProcessor
189
            name="%spellingQuickFixProcessor"
190
            name="%spellingQuickFixProcessor"
190
            class="org.eclipse.jdt.internal.ui.text.spelling.WordQuickFixProcessor"
191
            class="org.eclipse.ui.internal.texteditor.spelling.WordQuickFixProcessor"
191
            id= "org.eclipse.jdt.ui.text.correction.spelling.QuickFixProcessor">
192
            id= "org.eclipse.jdt.ui.text.correction.spelling.QuickFixProcessor">
192
            <handledMarkerTypes>
193
            <handledMarkerTypes>
193
                <markerType id="org.eclipse.jdt.ui.internal.spelling"/>
194
                <markerType id="org.eclipse.jdt.ui.internal.spelling"/>
194
	        </handledMarkerTypes>
195
	        </handledMarkerTypes>
195
      </quickFixProcessor>
196
      </quickFixProcessor>--> 
196
   </extension>
197
   </extension>
197
   <extension
198
   <extension
198
         point="org.eclipse.jdt.ui.quickAssistProcessors">
199
         point="org.eclipse.jdt.ui.quickAssistProcessors">
Lines 5600-5609 Link Here
5600
    <extension point="org.eclipse.ui.workbench.texteditor.spellingEngine">
5601
    <extension point="org.eclipse.ui.workbench.texteditor.spellingEngine">
5601
        <engine
5602
        <engine
5602
              preferencesClass="org.eclipse.jdt.internal.ui.preferences.SpellingPreferenceBlock"
5603
              preferencesClass="org.eclipse.jdt.internal.ui.preferences.SpellingPreferenceBlock"
5603
              label="%defaultSpellingEngine.label"
5604
              label="Java spelling engine"
5604
              class="org.eclipse.jdt.internal.ui.text.spelling.DefaultSpellingEngine"
5605
              class="org.eclipse.jdt.internal.ui.text.spelling.JavaSpellingEngine"
5605
              default="true"
5606
              default="false"
5606
              id="org.eclipse.jdt.internal.ui.text.spelling.DefaultSpellingEngine">
5607
              id="org.eclipse.jdt.internal.ui.text.spelling.JavaSpellingEngine"
5608
              contentType="org.eclipse.jdt.core.javaSource"> 
5609
        </engine>
5610
    </extension>
5611
    
5612
    <extension point="org.eclipse.ui.workbench.texteditor.spellingEngine">
5613
        <engine
5614
              preferencesClass="org.eclipse.jdt.internal.ui.preferences.SpellingPreferenceBlock"
5615
              label="Properties file spelling engine"
5616
              class="org.eclipse.jdt.internal.ui.text.spelling.PropertiesFileSpellingEngine"
5617
              default="false"
5618
              id="org.eclipse.jdt.internal.ui.text.spelling.PropertiesFileSpellingEngine"
5619
              contentType="org.eclipse.jdt.core.javaProperties">
5607
        </engine>
5620
        </engine>
5608
    </extension>
5621
    </extension>
5609
        
5622
        
(-)ui/org/eclipse/jdt/internal/ui/JavaPlugin.java (-1 / +1 lines)
Lines 61-66 Link Here
61
import org.eclipse.ui.texteditor.ChainedPreferenceStore;
61
import org.eclipse.ui.texteditor.ChainedPreferenceStore;
62
import org.eclipse.ui.texteditor.ConfigurationElementSorter;
62
import org.eclipse.ui.texteditor.ConfigurationElementSorter;
63
import org.eclipse.ui.texteditor.IDocumentProvider;
63
import org.eclipse.ui.texteditor.IDocumentProvider;
64
import org.eclipse.ui.texteditor.spelling.engine.SpellCheckEngine;
64
65
65
import org.eclipse.ui.editors.text.EditorsUI;
66
import org.eclipse.ui.editors.text.EditorsUI;
66
import org.eclipse.ui.editors.text.templates.ContributionContextTypeRegistry;
67
import org.eclipse.ui.editors.text.templates.ContributionContextTypeRegistry;
Lines 101-107 Link Here
101
import org.eclipse.jdt.internal.ui.text.folding.JavaFoldingStructureProviderRegistry;
102
import org.eclipse.jdt.internal.ui.text.folding.JavaFoldingStructureProviderRegistry;
102
import org.eclipse.jdt.internal.ui.text.java.ContentAssistHistory;
103
import org.eclipse.jdt.internal.ui.text.java.ContentAssistHistory;
103
import org.eclipse.jdt.internal.ui.text.java.hover.JavaEditorTextHoverDescriptor;
104
import org.eclipse.jdt.internal.ui.text.java.hover.JavaEditorTextHoverDescriptor;
104
import org.eclipse.jdt.internal.ui.text.spelling.SpellCheckEngine;
105
import org.eclipse.jdt.internal.ui.viewsupport.ImageDescriptorRegistry;
105
import org.eclipse.jdt.internal.ui.viewsupport.ImageDescriptorRegistry;
106
import org.eclipse.jdt.internal.ui.viewsupport.ImagesOnFileSystemRegistry;
106
import org.eclipse.jdt.internal.ui.viewsupport.ImagesOnFileSystemRegistry;
107
import org.eclipse.jdt.internal.ui.viewsupport.ProblemMarkerManager;
107
import org.eclipse.jdt.internal.ui.viewsupport.ProblemMarkerManager;
(-)ui/org/eclipse/jdt/internal/ui/preferences/SpellingConfigurationBlock.java (-1 / +2 lines)
Lines 52-57 Link Here
52
import org.eclipse.ui.ide.dialogs.EncodingFieldEditor;
52
import org.eclipse.ui.ide.dialogs.EncodingFieldEditor;
53
import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
53
import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
54
54
55
import org.eclipse.ui.texteditor.spelling.engine.SpellCheckEngine;
56
55
import org.eclipse.debug.ui.StringVariableSelectionDialog;
57
import org.eclipse.debug.ui.StringVariableSelectionDialog;
56
58
57
import org.eclipse.jdt.internal.corext.util.Messages;
59
import org.eclipse.jdt.internal.corext.util.Messages;
Lines 61-67 Link Here
61
import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
63
import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
62
import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
64
import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
63
import org.eclipse.jdt.internal.ui.dialogs.StatusUtil;
65
import org.eclipse.jdt.internal.ui.dialogs.StatusUtil;
64
import org.eclipse.jdt.internal.ui.text.spelling.SpellCheckEngine;
65
import org.eclipse.jdt.internal.ui.util.SWTUtil;
66
import org.eclipse.jdt.internal.ui.util.SWTUtil;
66
import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener;
67
import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener;
67
68
(-)ui/org/eclipse/jdt/internal/ui/propertiesfileeditor/PropertiesCorrectionProcessor.java (-2 / +2 lines)
Lines 28-34 Link Here
28
import org.eclipse.jface.text.source.ISourceViewer;
28
import org.eclipse.jface.text.source.ISourceViewer;
29
import org.eclipse.jface.text.source.TextInvocationContext;
29
import org.eclipse.jface.text.source.TextInvocationContext;
30
30
31
import org.eclipse.ui.texteditor.spelling.SpellingCorrectionProcessor;
31
import org.eclipse.ui.texteditor.spelling.correction.SpellingCorrectionProcessor;
32
32
33
import org.eclipse.ltk.core.refactoring.NullChange;
33
import org.eclipse.ltk.core.refactoring.NullChange;
34
34
Lines 48-54 Link Here
48
48
49
	private String fErrorMessage;
49
	private String fErrorMessage;
50
50
51
	private SpellingCorrectionProcessor fSpellingCorrectionProcessor;
51
	private org.eclipse.ui.texteditor.spelling.correction.SpellingCorrectionProcessor fSpellingCorrectionProcessor;
52
52
53
	private ICompletionProposal[] fPreComputedProposals;
53
	private ICompletionProposal[] fPreComputedProposals;
54
54
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/AddWordProposal.java (-174 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2009 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling;
13
14
import org.eclipse.swt.graphics.Image;
15
import org.eclipse.swt.graphics.Point;
16
import org.eclipse.swt.widgets.Shell;
17
18
import org.eclipse.jface.dialogs.IDialogConstants;
19
import org.eclipse.jface.dialogs.MessageDialogWithToggle;
20
21
import org.eclipse.jface.text.IDocument;
22
import org.eclipse.jface.text.contentassist.IContextInformation;
23
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
24
25
import org.eclipse.ui.dialogs.PreferencesUtil;
26
27
import org.eclipse.ui.texteditor.spelling.SpellingProblem;
28
29
import org.eclipse.jdt.internal.corext.util.Messages;
30
31
import org.eclipse.jdt.ui.PreferenceConstants;
32
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
33
34
import org.eclipse.jdt.internal.ui.JavaPlugin;
35
import org.eclipse.jdt.internal.ui.JavaPluginImages;
36
import org.eclipse.jdt.internal.ui.JavaUIMessages;
37
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine;
38
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker;
39
40
/**
41
 * Proposal to add the unknown word to the dictionaries.
42
 *
43
 * @since 3.0
44
 */
45
public class AddWordProposal implements IJavaCompletionProposal {
46
47
	private static final String PREF_KEY_DO_NOT_ASK= "do_not_ask_to_install_user_dictionary"; //$NON-NLS-1$
48
49
	/** The invocation context */
50
	private final IQuickAssistInvocationContext fContext;
51
52
	/** The word to add */
53
	private final String fWord;
54
55
56
	/**
57
	 * Creates a new add word proposal
58
	 *
59
	 * @param word
60
	 *                   The word to add
61
	 * @param context
62
	 *                   The invocation context
63
	 */
64
	public AddWordProposal(final String word, final IQuickAssistInvocationContext context) {
65
		fContext= context;
66
		fWord= word;
67
	}
68
69
	/*
70
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(org.eclipse.jface.text.IDocument)
71
	 */
72
	public final void apply(final IDocument document) {
73
74
		final ISpellCheckEngine engine= SpellCheckEngine.getInstance();
75
		final ISpellChecker checker= engine.getSpellChecker();
76
77
		if (checker == null)
78
			return;
79
80
		if (!checker.acceptsWords()) {
81
			final Shell shell;
82
			if (fContext != null && fContext.getSourceViewer() != null)
83
				shell= fContext.getSourceViewer().getTextWidget().getShell();
84
			else
85
				shell= JavaPlugin.getActiveWorkbenchShell();
86
87
			if (!canAskToConfigure() || !askUserToConfigureUserDictionary(shell))
88
				return;
89
90
			String[] preferencePageIds= new String[] { "org.eclipse.ui.editors.preferencePages.Spelling" }; //$NON-NLS-1$
91
			PreferencesUtil.createPreferenceDialogOn(shell, preferencePageIds[0], preferencePageIds, null).open();
92
		}
93
94
		if (checker.acceptsWords()) {
95
			checker.addWord(fWord);
96
			if (fContext != null && fContext.getSourceViewer() != null)
97
				SpellingProblem.removeAll(fContext.getSourceViewer(), fWord);
98
		}
99
	}
100
101
	/**
102
	 * Asks the user whether he wants to configure a user dictionary.
103
	 * 
104
	 * @param shell the shell
105
	 * @return <code>true</code> if the user wants to configure the user dictionary
106
	 * @since 3.3
107
	 */
108
	private boolean askUserToConfigureUserDictionary(Shell shell) {
109
		MessageDialogWithToggle toggleDialog= MessageDialogWithToggle.openYesNoQuestion(
110
				shell,
111
				JavaUIMessages.Spelling_add_askToConfigure_title,
112
				JavaUIMessages.Spelling_add_askToConfigure_question,
113
				JavaUIMessages.Spelling_add_askToConfigure_ignoreMessage,
114
				false,
115
				null,
116
				null);
117
118
		PreferenceConstants.getPreferenceStore().setValue(PREF_KEY_DO_NOT_ASK, toggleDialog.getToggleState());
119
120
		return toggleDialog.getReturnCode() == IDialogConstants.YES_ID;
121
	}
122
123
	/**
124
	 * Tells whether this proposal can ask to
125
	 * configure a user dictionary.
126
	 *
127
	 * @return <code>true</code> if it can ask the user
128
	 */
129
	static boolean canAskToConfigure() {
130
		return !PreferenceConstants.getPreferenceStore().getBoolean(PREF_KEY_DO_NOT_ASK);
131
	}
132
133
	/*
134
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo()
135
	 */
136
	public String getAdditionalProposalInfo() {
137
		return Messages.format(JavaUIMessages.Spelling_add_info, new String[] { WordCorrectionProposal.getHtmlRepresentation(fWord)});
138
	}
139
140
	/*
141
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getContextInformation()
142
	 */
143
	public final IContextInformation getContextInformation() {
144
		return null;
145
	}
146
147
	/*
148
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString()
149
	 */
150
	public String getDisplayString() {
151
		return Messages.format(JavaUIMessages.Spelling_add_label, new String[] { fWord });
152
	}
153
154
	/*
155
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage()
156
	 */
157
	public Image getImage() {
158
		return JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_ADD);
159
	}
160
161
	/*
162
	 * @see org.eclipse.jdt.ui.text.java.IJavaCompletionProposal#getRelevance()
163
	 */
164
	public int getRelevance() {
165
		return Integer.MIN_VALUE;
166
	}
167
168
	/*
169
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getSelection(org.eclipse.jface.text.IDocument)
170
	 */
171
	public final Point getSelection(final IDocument document) {
172
		return new Point(fContext.getOffset(), fContext.getLength());
173
	}
174
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/ChangeCaseProposal.java (-46 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2009 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling;
13
14
import java.util.Locale;
15
16
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
17
18
import org.eclipse.jdt.internal.ui.JavaUIMessages;
19
20
/**
21
 * Proposal to change the letter case of a word.
22
 *
23
 * @since 3.0
24
 */
25
public class ChangeCaseProposal extends WordCorrectionProposal {
26
27
	/**
28
	 * Creates a new change case proposal.
29
	 * 
30
	 * @param arguments The problem arguments associated with the spelling problem
31
	 * @param offset The offset in the document where to apply the proposal
32
	 * @param length The length in the document to apply the proposal
33
	 * @param context The invocation context for this proposal
34
	 * @param locale The locale to use for the case change
35
	 */
36
	public ChangeCaseProposal(final String[] arguments, final int offset, final int length, final IQuickAssistInvocationContext context, final Locale locale) {
37
		super(Character.isLowerCase(arguments[0].charAt(0)) ? Character.toUpperCase(arguments[0].charAt(0)) + arguments[0].substring(1) : arguments[0], arguments, offset, length, context, Integer.MAX_VALUE);
38
	}
39
40
	/*
41
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString()
42
	 */
43
	public String getDisplayString() {
44
		return JavaUIMessages.Spelling_case_label;
45
	}
46
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/DefaultSpellingEngine.java (-95 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling;
13
14
import java.util.HashMap;
15
import java.util.Map;
16
17
import org.eclipse.core.runtime.IProgressMonitor;
18
import org.eclipse.core.runtime.Platform;
19
import org.eclipse.core.runtime.content.IContentType;
20
import org.eclipse.core.runtime.content.IContentTypeManager;
21
22
import org.eclipse.jface.text.IDocument;
23
import org.eclipse.jface.text.IRegion;
24
25
import org.eclipse.ui.texteditor.spelling.ISpellingEngine;
26
import org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector;
27
import org.eclipse.ui.texteditor.spelling.SpellingContext;
28
29
import org.eclipse.jdt.core.JavaCore;
30
31
/**
32
 * Default spelling engine.
33
 * <p>
34
 * Internally this spelling engine uses a different spelling engine depending on
35
 * the {@linkplain IContentType content type}. Currently this engine supports
36
 * the text, Java and Java properties file content types.
37
 * </p>
38
 *
39
 * @since 3.1
40
 */
41
public class DefaultSpellingEngine implements ISpellingEngine {
42
43
	/** Text content type */
44
	private static final IContentType TEXT_CONTENT_TYPE= Platform.getContentTypeManager().getContentType(IContentTypeManager.CT_TEXT);
45
46
	/** Java source content type */
47
	private static final IContentType JAVA_CONTENT_TYPE= Platform.getContentTypeManager().getContentType(JavaCore.JAVA_SOURCE_CONTENT_TYPE);
48
49
	/** Java properties content type */
50
	private static final IContentType PROPERTIES_CONTENT_TYPE= Platform.getContentTypeManager().getContentType("org.eclipse.jdt.core.javaProperties"); //$NON-NLS-1$
51
52
	/** Available spelling engines by content type */
53
	private Map fEngines= new HashMap();
54
55
	/**
56
	 * Initialize concrete engines.
57
	 */
58
	public DefaultSpellingEngine() {
59
		if (JAVA_CONTENT_TYPE != null)
60
			fEngines.put(JAVA_CONTENT_TYPE, new JavaSpellingEngine());
61
		if (PROPERTIES_CONTENT_TYPE != null)
62
			fEngines.put(PROPERTIES_CONTENT_TYPE, new PropertiesFileSpellingEngine());
63
		if (TEXT_CONTENT_TYPE != null)
64
			fEngines.put(TEXT_CONTENT_TYPE, new TextSpellingEngine());
65
	}
66
67
	/*
68
	 * @see org.eclipse.ui.texteditor.spelling.ISpellingEngine#check(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IRegion[], org.eclipse.ui.texteditor.spelling.SpellingContext, org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector, org.eclipse.core.runtime.IProgressMonitor)
69
	 */
70
	public void check(IDocument document, IRegion[] regions, SpellingContext context, ISpellingProblemCollector collector, IProgressMonitor monitor) {
71
		ISpellingEngine engine= getEngine(context.getContentType());
72
		if (engine == null)
73
			engine= getEngine(TEXT_CONTENT_TYPE);
74
		if (engine != null)
75
			engine.check(document, regions, context, collector, monitor);
76
	}
77
78
	/**
79
	 * Returns a spelling engine for the given content type or
80
	 * <code>null</code> if none could be found.
81
	 *
82
	 * @param contentType the content type
83
	 * @return a spelling engine for the given content type or
84
	 *         <code>null</code> if none could be found
85
	 */
86
	private ISpellingEngine getEngine(IContentType contentType) {
87
		if (contentType == null)
88
			return null;
89
90
		if (fEngines.containsKey(contentType))
91
			return (ISpellingEngine) fEngines.get(contentType);
92
93
		return getEngine(contentType.getBaseType());
94
	}
95
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/DisableSpellCheckingProposal.java (-99 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2007, 2009 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.ui.text.spelling;
12
13
import org.eclipse.swt.graphics.Image;
14
import org.eclipse.swt.graphics.Point;
15
16
import org.eclipse.jface.preference.IPreferenceStore;
17
18
import org.eclipse.jface.text.IDocument;
19
import org.eclipse.jface.text.contentassist.IContextInformation;
20
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
21
22
import org.eclipse.ui.texteditor.spelling.SpellingService;
23
24
import org.eclipse.ui.editors.text.EditorsUI;
25
26
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
27
28
import org.eclipse.jdt.internal.ui.JavaPluginImages;
29
import org.eclipse.jdt.internal.ui.JavaUIMessages;
30
31
32
/**
33
 * Proposal to disable spell checking.
34
 *
35
 * @since 3.3
36
 */
37
public class DisableSpellCheckingProposal implements IJavaCompletionProposal {
38
39
	/** The invocation context */
40
	private IQuickAssistInvocationContext fContext;
41
42
	/**
43
	 * Creates a new proposal.
44
	 *
45
	 * @param context the invocation context
46
	 */
47
	public DisableSpellCheckingProposal(IQuickAssistInvocationContext context) {
48
		fContext= context;
49
	}
50
51
	/*
52
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(org.eclipse.jface.text.IDocument)
53
	 */
54
	public final void apply(final IDocument document) {
55
		IPreferenceStore store= EditorsUI.getPreferenceStore();
56
		store.setValue(SpellingService.PREFERENCE_SPELLING_ENABLED, false);
57
	}
58
59
	/*
60
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo()
61
	 */
62
	public String getAdditionalProposalInfo() {
63
		return JavaUIMessages.Spelling_disable_info;
64
	}
65
66
	/*
67
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getContextInformation()
68
	 */
69
	public final IContextInformation getContextInformation() {
70
		return null;
71
	}
72
73
	/*
74
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString()
75
	 */
76
	public String getDisplayString() {
77
		return JavaUIMessages.Spelling_disable_label;
78
	}
79
80
	/*
81
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage()
82
	 */
83
	public Image getImage() {
84
		return JavaPluginImages.get(JavaPluginImages.IMG_OBJS_NLS_NEVER_TRANSLATE);
85
	}
86
	/*
87
	 * @see org.eclipse.jdt.ui.text.java.IJavaCompletionProposal#getRelevance()
88
	 */
89
	public final int getRelevance() {
90
		return Integer.MIN_VALUE + 1;
91
	}
92
93
	/*
94
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getSelection(org.eclipse.jface.text.IDocument)
95
	 */
96
	public final Point getSelection(final IDocument document) {
97
		return new Point(fContext.getOffset(), fContext.getLength());
98
	}
99
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/HtmlTagDictionary.java (-67 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling;
13
14
import java.net.URL;
15
16
import org.eclipse.jdt.internal.ui.text.javadoc.IHtmlTagConstants;
17
import org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary;
18
19
/**
20
 * Dictionary for html tags.
21
 *
22
 * @since 3.0
23
 */
24
public class HtmlTagDictionary extends AbstractSpellDictionary {
25
26
	/*
27
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary#getName()
28
	 */
29
	protected final URL getURL() {
30
		return null;
31
	}
32
33
	/*
34
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary#isCorrect(java.lang.String)
35
	 */
36
	public boolean isCorrect(final String word) {
37
38
		if (word.charAt(0) == IHtmlTagConstants.HTML_TAG_PREFIX)
39
			return super.isCorrect(word);
40
41
		return false;
42
	}
43
44
	/*
45
	 * @see org.eclipse.jdt.ui.text.spelling.engine.AbstractSpellDictionary#load(java.net.URL)
46
	 */
47
	protected synchronized boolean load(final URL url) {
48
49
		unload();
50
51
		for (int index= 0; index < IHtmlTagConstants.HTML_GENERAL_TAGS.length; index++) {
52
53
			hashWord(IHtmlTagConstants.HTML_TAG_PREFIX + IHtmlTagConstants.HTML_GENERAL_TAGS[index] + IHtmlTagConstants.HTML_TAG_POSTFIX);
54
			hashWord(IHtmlTagConstants.HTML_CLOSE_PREFIX + IHtmlTagConstants.HTML_GENERAL_TAGS[index] + IHtmlTagConstants.HTML_TAG_POSTFIX);
55
		}
56
		return true;
57
	}
58
59
	/*
60
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary#stripNonLetters(java.lang.String)
61
	 * @since 3.3
62
	 */
63
	protected String stripNonLetters(String word) {
64
		return word;
65
	}
66
67
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/JavaDocTagDictionary.java (-70 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.ui.text.spelling;
12
13
import java.net.URL;
14
15
import org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary;
16
17
18
/**
19
 * Dictionary for Javadoc tags.
20
 *
21
 * @since 3.0
22
 */
23
public class JavaDocTagDictionary extends AbstractSpellDictionary implements IJavaDocTagConstants {
24
25
	/*
26
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary#getName()
27
	 */
28
	protected final URL getURL() {
29
		return null;
30
	}
31
32
	/*
33
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary#isCorrect(java.lang.String)
34
	 */
35
	public boolean isCorrect(final String word) {
36
37
		if (word.charAt(0) == JAVADOC_TAG_PREFIX)
38
			return super.isCorrect(word);
39
40
		return false;
41
	}
42
43
	/*
44
	 * @see org.eclipse.jdt.ui.text.spelling.engine.AbstractSpellDictionary#load(java.net.URL)
45
	 */
46
	protected synchronized boolean load(final URL url) {
47
48
		unload();
49
50
		for (int index= 0; index < JAVADOC_LINK_TAGS.length; index++)
51
			hashWord(JAVADOC_LINK_TAGS[index]);
52
53
		for (int index= 0; index < JAVADOC_ROOT_TAGS.length; index++)
54
			hashWord(JAVADOC_ROOT_TAGS[index]);
55
56
		for (int index= 0; index < JAVADOC_PARAM_TAGS.length; index++)
57
			hashWord(JAVADOC_PARAM_TAGS[index]);
58
59
		return true;
60
	}
61
62
	/*
63
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary#stripNonLetters(java.lang.String)
64
	 * @since 3.3
65
	 */
66
	protected String stripNonLetters(String word) {
67
		return word;
68
	}
69
70
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/JavaSpellingEngine.java (-1 / +4 lines)
Lines 19-30 Link Here
19
import org.eclipse.jface.text.ITypedRegion;
19
import org.eclipse.jface.text.ITypedRegion;
20
import org.eclipse.jface.text.TextUtilities;
20
import org.eclipse.jface.text.TextUtilities;
21
21
22
22
import org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector;
23
import org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector;
24
import org.eclipse.ui.texteditor.spelling.SpellCheckIterator;
25
import org.eclipse.ui.texteditor.spelling.engine.ISpellChecker;
26
import org.eclipse.ui.texteditor.spelling.engine.SpellingEngine;
23
27
24
import org.eclipse.jdt.ui.PreferenceConstants;
28
import org.eclipse.jdt.ui.PreferenceConstants;
25
import org.eclipse.jdt.ui.text.IJavaPartitions;
29
import org.eclipse.jdt.ui.text.IJavaPartitions;
26
30
27
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker;
28
31
29
32
30
/**
33
/**
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/JavaSpellingProblem.java (-239 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2009 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.ui.text.spelling;
12
13
import java.util.ArrayList;
14
import java.util.Collections;
15
import java.util.List;
16
17
import org.eclipse.core.runtime.Assert;
18
19
import org.eclipse.jface.text.BadLocationException;
20
import org.eclipse.jface.text.IDocument;
21
import org.eclipse.jface.text.IRegion;
22
import org.eclipse.jface.text.contentassist.ICompletionProposal;
23
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
24
import org.eclipse.jface.text.source.TextInvocationContext;
25
26
import org.eclipse.ui.texteditor.spelling.SpellingProblem;
27
28
import org.eclipse.jdt.internal.corext.util.Messages;
29
30
import org.eclipse.jdt.ui.PreferenceConstants;
31
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
32
33
import org.eclipse.jdt.internal.ui.JavaUIMessages;
34
import org.eclipse.jdt.internal.ui.text.javadoc.IHtmlTagConstants;
35
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine;
36
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker;
37
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEvent;
38
import org.eclipse.jdt.internal.ui.text.spelling.engine.RankedWordProposal;
39
40
/**
41
 * A {@link SpellingProblem} that adapts a {@link ISpellEvent}.
42
 * <p>
43
 * TODO: remove {@link ISpellEvent} notification mechanism
44
 * </p>
45
 */
46
public class JavaSpellingProblem extends SpellingProblem {
47
48
	/** Spell event */
49
	private ISpellEvent fSpellEvent;
50
51
	/**
52
	 * The associated document.
53
	 *
54
	 * @since 3.3
55
	 */
56
	private IDocument fDocument;
57
58
	/**
59
	 * Initialize with the given spell event.
60
	 *
61
	 * @param spellEvent the spell event
62
	 * @param document the document
63
	 */
64
	public JavaSpellingProblem(ISpellEvent spellEvent, IDocument document) {
65
		Assert.isLegal(document != null);
66
		Assert.isLegal(spellEvent != null);
67
		fSpellEvent= spellEvent;
68
		fDocument= document;
69
	}
70
71
	/*
72
	 * @see org.eclipse.ui.texteditor.spelling.SpellingProblem#getOffset()
73
	 */
74
	public int getOffset() {
75
		return fSpellEvent.getBegin();
76
	}
77
78
	/*
79
	 * @see org.eclipse.ui.texteditor.spelling.SpellingProblem#getLength()
80
	 */
81
	public int getLength() {
82
		return fSpellEvent.getEnd() - fSpellEvent.getBegin() + 1;
83
	}
84
85
	/*
86
	 * @see org.eclipse.ui.texteditor.spelling.SpellingProblem#getMessage()
87
	 */
88
	public String getMessage() {
89
		if (isSentenceStart() && isDictionaryMatch())
90
			return Messages.format(JavaUIMessages.Spelling_error_case_label, new String[] { fSpellEvent.getWord() });
91
92
		return Messages.format(JavaUIMessages.Spelling_error_label, new String[] { fSpellEvent.getWord() });
93
	}
94
95
	/*
96
	 * @see org.eclipse.ui.texteditor.spelling.SpellingProblem#getProposals()
97
	 */
98
	public ICompletionProposal[] getProposals() {
99
		return getProposals(null);
100
	}
101
102
	/*
103
	 * @see org.eclipse.ui.texteditor.spelling.SpellingProblem#getProposals(org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext)
104
	 * @since 3.4
105
	 */
106
	public ICompletionProposal[] getProposals(IQuickAssistInvocationContext context) {
107
		String[] arguments= getArguments();
108
		if (arguments == null)
109
			return new ICompletionProposal[0];
110
111
		if (arguments[0].indexOf('&') != -1 && isIgnoringAmpersand())
112
			return new ICompletionProposal[0]; // no proposals for now
113
114
		final int threshold= PreferenceConstants.getPreferenceStore().getInt(PreferenceConstants.SPELLING_PROPOSAL_THRESHOLD);
115
		int size= 0;
116
		List proposals= null;
117
118
		RankedWordProposal proposal= null;
119
		IJavaCompletionProposal[] result= null;
120
		int index= 0;
121
122
		boolean fixed= false;
123
		boolean match= false;
124
		boolean sentence= false;
125
126
		final ISpellCheckEngine engine= SpellCheckEngine.getInstance();
127
		final ISpellChecker checker= engine.getSpellChecker();
128
129
		if (checker != null) {
130
131
			if (context == null)
132
				context= new TextInvocationContext(null, getOffset(), getLength());
133
			else
134
				context= new TextInvocationContext(context.getSourceViewer(), getOffset(), getLength());
135
136
			// FIXME: this is a pretty ugly hack
137
			fixed= arguments[0].charAt(0) == IHtmlTagConstants.HTML_TAG_PREFIX
138
					|| arguments[0].charAt(0) == IJavaDocTagConstants.JAVADOC_TAG_PREFIX;
139
140
			if ((sentence && match) && !fixed)
141
				result= new IJavaCompletionProposal[] { new ChangeCaseProposal(
142
						arguments, getOffset(), getLength(), context, engine
143
								.getLocale()) };
144
			else {
145
146
				proposals= new ArrayList(checker.getProposals(arguments[0],
147
						sentence));
148
				size= proposals.size();
149
150
				if (threshold > 0 && size > threshold) {
151
152
					Collections.sort(proposals);
153
					proposals= proposals
154
							.subList(size - threshold - 1, size - 1);
155
					size= proposals.size();
156
				}
157
158
				boolean extendable= !fixed ? (checker.acceptsWords() || AddWordProposal.canAskToConfigure()) : false;
159
				result= new IJavaCompletionProposal[size + (extendable ? 3 : 2)];
160
161
				for (index= 0; index < size; index++) {
162
163
					proposal= (RankedWordProposal) proposals.get(index);
164
					result[index]= new WordCorrectionProposal(proposal
165
							.getText(), arguments, getOffset(), getLength(),
166
							context, proposal.getRank());
167
				}
168
169
				if (extendable)
170
					result[index++]= new AddWordProposal(arguments[0], context);
171
172
				result[index++]= new WordIgnoreProposal(arguments[0], context);
173
				result[index++]= new DisableSpellCheckingProposal(context);
174
			}
175
		}
176
177
		return result;
178
	}
179
180
	private boolean isIgnoringAmpersand() {
181
		return PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.SPELLING_IGNORE_AMPERSAND_IN_PROPERTIES);
182
	}
183
184
	public String[] getArguments() {
185
186
		String prefix= ""; //$NON-NLS-1$
187
		String postfix= ""; //$NON-NLS-1$
188
		String word;
189
		try {
190
			word= fDocument.get(getOffset(), getLength());
191
		} catch (BadLocationException e) {
192
			return null;
193
		}
194
195
		try {
196
197
			IRegion line= fDocument.getLineInformationOfOffset(getOffset());
198
			prefix= fDocument.get(line.getOffset(), getOffset() - line.getOffset());
199
			int postfixStart= getOffset() + getLength();
200
			postfix= fDocument.get(postfixStart, line.getOffset() + line.getLength() - postfixStart);
201
202
		} catch (BadLocationException exception) {
203
			// Do nothing
204
		}
205
		return new String[] {
206
				word,
207
				prefix,
208
				postfix,
209
				isSentenceStart() ? Boolean.toString(true) : Boolean
210
						.toString(false),
211
				isDictionaryMatch() ? Boolean.toString(true) : Boolean
212
						.toString(false) };
213
	}
214
215
	/**
216
	 * Returns <code>true</code> iff the corresponding word was found in the dictionary.
217
	 * <p>
218
	 * NOTE: to be removed, see {@link #getProposals()}
219
	 * </p>
220
	 *
221
	 * @return <code>true</code> iff the corresponding word was found in the dictionary
222
	 */
223
	public boolean isDictionaryMatch() {
224
		return fSpellEvent.isMatch();
225
	}
226
227
	/**
228
	 * Returns <code>true</code> iff the corresponding word starts a sentence.
229
	 * <p>
230
	 * NOTE: to be removed, see {@link #getProposals()}
231
	 * </p>
232
	 *
233
	 * @return <code>true</code> iff the corresponding word starts a sentence
234
	 */
235
	public boolean isSentenceStart() {
236
		return fSpellEvent.isStart();
237
	}
238
239
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/JavaSpellingReconcileStrategy.java (-3 / +4 lines)
Lines 27-32 Link Here
27
import org.eclipse.ui.texteditor.spelling.SpellingProblem;
27
import org.eclipse.ui.texteditor.spelling.SpellingProblem;
28
import org.eclipse.ui.texteditor.spelling.SpellingReconcileStrategy;
28
import org.eclipse.ui.texteditor.spelling.SpellingReconcileStrategy;
29
import org.eclipse.ui.texteditor.spelling.SpellingService;
29
import org.eclipse.ui.texteditor.spelling.SpellingService;
30
import org.eclipse.ui.texteditor.spelling.TextSpellingProblem;
30
31
31
import org.eclipse.ui.editors.text.EditorsUI;
32
import org.eclipse.ui.editors.text.EditorsUI;
32
33
Lines 60-68 Link Here
60
					String word= getDocument().get(problem.getOffset(), problem.getLength());
61
					String word= getDocument().get(problem.getOffset(), problem.getLength());
61
					boolean dictionaryMatch= false;
62
					boolean dictionaryMatch= false;
62
					boolean sentenceStart= false;
63
					boolean sentenceStart= false;
63
					if (problem instanceof JavaSpellingProblem) {
64
					if (problem instanceof TextSpellingProblem) {
64
						dictionaryMatch= ((JavaSpellingProblem)problem).isDictionaryMatch();
65
						dictionaryMatch= ((TextSpellingProblem)problem).isDictionaryMatch();
65
						sentenceStart= ((JavaSpellingProblem) problem).isSentenceStart();
66
						sentenceStart= ((TextSpellingProblem)problem).isSentenceStart();
66
					}
67
					}
67
					// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=81514
68
					// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=81514
68
					IEditorInput editorInput= fEditor.getEditorInput();
69
					IEditorInput editorInput= fEditor.getEditorInput();
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/PropertiesFileSpellCheckIterator.java (+2 lines)
Lines 17-22 Link Here
17
import org.eclipse.jface.text.IDocument;
17
import org.eclipse.jface.text.IDocument;
18
import org.eclipse.jface.text.IRegion;
18
import org.eclipse.jface.text.IRegion;
19
19
20
import org.eclipse.ui.texteditor.spelling.SpellCheckIterator;
21
20
22
21
/**
23
/**
22
 * Iterator to spell check Java properties files
24
 * Iterator to spell check Java properties files
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/PropertiesFileSpellingEngine.java (-1 / +4 lines)
Lines 26-38 Link Here
26
import org.eclipse.jface.text.TextUtilities;
26
import org.eclipse.jface.text.TextUtilities;
27
import org.eclipse.jface.text.TypedRegion;
27
import org.eclipse.jface.text.TypedRegion;
28
28
29
29
import org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector;
30
import org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector;
31
import org.eclipse.ui.texteditor.spelling.SpellCheckIterator;
32
import org.eclipse.ui.texteditor.spelling.engine.ISpellChecker;
33
import org.eclipse.ui.texteditor.spelling.engine.SpellingEngine;
30
34
31
import org.eclipse.jdt.ui.PreferenceConstants;
35
import org.eclipse.jdt.ui.PreferenceConstants;
32
36
33
import org.eclipse.jdt.internal.ui.JavaPlugin;
37
import org.eclipse.jdt.internal.ui.JavaPlugin;
34
import org.eclipse.jdt.internal.ui.propertiesfileeditor.IPropertiesFilePartitions;
38
import org.eclipse.jdt.internal.ui.propertiesfileeditor.IPropertiesFilePartitions;
35
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker;
36
39
37
/**
40
/**
38
 * Properties file spelling engine
41
 * Properties file spelling engine
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/SpellCheckEngine.java (-502 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.ui.text.spelling;
12
13
import java.io.File;
14
import java.io.IOException;
15
import java.io.InputStream;
16
import java.net.MalformedURLException;
17
import java.net.URL;
18
import java.util.Collections;
19
import java.util.Enumeration;
20
import java.util.HashMap;
21
import java.util.HashSet;
22
import java.util.Iterator;
23
import java.util.Locale;
24
import java.util.Map;
25
import java.util.Map.Entry;
26
import java.util.Set;
27
28
import org.eclipse.core.variables.IStringVariableManager;
29
import org.eclipse.core.variables.VariablesPlugin;
30
31
import org.eclipse.core.runtime.CoreException;
32
import org.eclipse.core.runtime.FileLocator;
33
34
import org.eclipse.jface.preference.IPreferenceStore;
35
import org.eclipse.jface.util.IPropertyChangeListener;
36
import org.eclipse.jface.util.PropertyChangeEvent;
37
38
import org.eclipse.ui.texteditor.spelling.SpellingService;
39
40
import org.eclipse.ui.editors.text.EditorsUI;
41
42
import org.eclipse.jdt.ui.PreferenceConstants;
43
44
import org.eclipse.jdt.internal.ui.JavaPlugin;
45
import org.eclipse.jdt.internal.ui.text.spelling.engine.DefaultSpellChecker;
46
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine;
47
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker;
48
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary;
49
import org.eclipse.jdt.internal.ui.text.spelling.engine.LocaleSensitiveSpellDictionary;
50
import org.eclipse.jdt.internal.ui.text.spelling.engine.PersistentSpellDictionary;
51
52
53
/**
54
 * Spell check engine for Java source spell checking.
55
 *
56
 * @since 3.0
57
 */
58
public class SpellCheckEngine implements ISpellCheckEngine, IPropertyChangeListener {
59
60
	/** The dictionary location */
61
	public static final String DICTIONARY_LOCATION= "dictionaries/"; //$NON-NLS-1$
62
63
	/** The singleton engine instance */
64
	private static ISpellCheckEngine fgEngine= null;
65
66
	/**
67
	 * Caches the locales of installed dictionaries.
68
	 *
69
	 * @since 3.3
70
	 */
71
	private static Set fgLocalesWithInstalledDictionaries;
72
73
	/**
74
	 * Returns the locales for which this
75
	 * spell check engine has dictionaries in certain location.
76
	 *
77
	 * @param location dictionaries location
78
	 * @return The available locales for this engine
79
	 */
80
	private static Set getLocalesWithInstalledDictionaries(URL location) {
81
		String[] fileNames;
82
		try {
83
			URL url= FileLocator.toFileURL(location);
84
			File file= new File(url.getFile());
85
			if (!file.isDirectory())
86
				return Collections.EMPTY_SET;
87
			fileNames= file.list();
88
			if (fileNames == null)
89
				return Collections.EMPTY_SET;
90
		} catch (IOException ex) {
91
			JavaPlugin.log(ex);
92
			return Collections.EMPTY_SET;
93
		}
94
95
		Set localesWithInstalledDictionaries= new HashSet();
96
		int fileNameCount= fileNames.length;
97
		for (int i= 0; i < fileNameCount; i++) {
98
			String fileName= fileNames[i];
99
			int localeEnd= fileName.indexOf(".dictionary"); //$NON-NLS-1$
100
			if (localeEnd > 1) {
101
				String localeName= fileName.substring(0, localeEnd);
102
				int languageEnd=localeName.indexOf('_');
103
				if (languageEnd == -1)
104
					localesWithInstalledDictionaries.add(new Locale(localeName));
105
				else if (languageEnd == 2 && localeName.length() == 5)
106
					localesWithInstalledDictionaries.add(new Locale(localeName.substring(0, 2), localeName.substring(3)));
107
				else if (localeName.length() > 6 && localeName.charAt(5) == '_')
108
					localesWithInstalledDictionaries.add(new Locale(localeName.substring(0, 2), localeName.substring(3, 5), localeName.substring(6)));
109
			}
110
		}
111
112
		return localesWithInstalledDictionaries;
113
	}
114
115
116
	/**
117
	 * Returns the locales for which this
118
	 * spell check engine has dictionaries.
119
	 *
120
	 * @return The available locales for this engine
121
	 */
122
	public static Set getLocalesWithInstalledDictionaries() {
123
		if (fgLocalesWithInstalledDictionaries != null)
124
			return fgLocalesWithInstalledDictionaries;
125
126
		Enumeration locations;
127
		try {
128
			locations= getDictionaryLocations();
129
			if (locations == null)
130
				return fgLocalesWithInstalledDictionaries= Collections.EMPTY_SET;
131
		} catch (IOException ex) {
132
			JavaPlugin.log(ex);
133
			return fgLocalesWithInstalledDictionaries= Collections.EMPTY_SET;
134
		}
135
136
		fgLocalesWithInstalledDictionaries= new HashSet();
137
138
		while (locations.hasMoreElements()) {
139
			URL location= (URL) locations.nextElement();
140
			Set locales= getLocalesWithInstalledDictionaries(location);
141
			fgLocalesWithInstalledDictionaries.addAll(locales);
142
		}
143
144
		return fgLocalesWithInstalledDictionaries;
145
	}
146
147
	/**
148
	 * Returns the default locale for this engine.
149
	 *
150
	 * @return The default locale
151
	 */
152
	public static Locale getDefaultLocale() {
153
		return Locale.getDefault();
154
	}
155
156
	/**
157
	 * Returns the dictionary closest to the given locale.
158
	 *
159
	 * @param locale the locale
160
	 * @return the dictionary or <code>null</code> if none is suitable
161
	 * @since 3.3
162
	 */
163
	public ISpellDictionary findDictionary(Locale locale) {
164
		ISpellDictionary dictionary= (ISpellDictionary)fLocaleDictionaries.get(locale);
165
		if (dictionary != null)
166
			return dictionary;
167
168
		// Try same language
169
		String language= locale.getLanguage();
170
		Iterator iter= fLocaleDictionaries.entrySet().iterator();
171
		while (iter.hasNext()) {
172
			Entry entry= (Entry)iter.next();
173
			Locale dictLocale= (Locale)entry.getKey();
174
			if (dictLocale.getLanguage().equals(language))
175
				return (ISpellDictionary)entry.getValue();
176
		}
177
178
		return null;
179
	}
180
181
	/*
182
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine#findDictionary(java.util.Locale)
183
	 * @since 3.3
184
	 */
185
	public static Locale findClosestLocale(Locale locale) {
186
		if (locale == null || locale.toString().length() == 0)
187
			return locale;
188
189
		if (getLocalesWithInstalledDictionaries().contains(locale))
190
			return locale;
191
192
		// Try same language
193
		String language= locale.getLanguage();
194
		Iterator iter= getLocalesWithInstalledDictionaries().iterator();
195
		while (iter.hasNext()) {
196
			Locale dictLocale= (Locale)iter.next();
197
			if (dictLocale.getLanguage().equals(language))
198
				return dictLocale;
199
		}
200
201
		// Try whether American English is present
202
		Locale defaultLocale= Locale.US;
203
		if (getLocalesWithInstalledDictionaries().contains(defaultLocale))
204
			return defaultLocale;
205
206
		return null;
207
	}
208
209
	/**
210
	 * Returns the enumeration of URLs for the dictionary locations where
211
	 * the Platform dictionaries are located.
212
	 * <p>
213
	 * This is in <code>org.eclipse.jdt.ui/dictionaries/</code>
214
	 * which can also be populated via fragments.
215
	 * </p>
216
	 *
217
	 * @throws IOException if there is an I/O error
218
	 * @return The dictionary locations, or <code>null</code> iff the locations are not known
219
	 */
220
	public static Enumeration getDictionaryLocations() throws IOException {
221
		final JavaPlugin plugin= JavaPlugin.getDefault();
222
		if (plugin != null)
223
			return plugin.getBundle().getResources("/" + DICTIONARY_LOCATION); //$NON-NLS-1$
224
		return null;
225
	}
226
227
	/**
228
	 * Returns the singleton instance of the spell check engine.
229
	 *
230
	 * @return The singleton instance of the spell check engine
231
	 */
232
	public static synchronized final ISpellCheckEngine getInstance() {
233
234
		if (fgEngine == null)
235
			fgEngine= new SpellCheckEngine();
236
237
		return fgEngine;
238
	}
239
240
	/**
241
	 * Shuts down the singleton instance of the spell check engine.
242
	 */
243
	public static synchronized final void shutdownInstance() {
244
		if (fgEngine != null) {
245
			fgEngine.shutdown();
246
			fgEngine= null;
247
		}
248
	}
249
250
	/** The registered locale insensitive dictionaries */
251
	private Set fGlobalDictionaries= new HashSet();
252
253
	/** The spell checker for fLocale */
254
	private ISpellChecker fChecker= null;
255
256
	/** The registered locale sensitive dictionaries */
257
	private Map fLocaleDictionaries= new HashMap();
258
259
	/** The user dictionary */
260
	private ISpellDictionary fUserDictionary= null;
261
262
	/**
263
	 * Creates a new spell check manager.
264
	 */
265
	private SpellCheckEngine() {
266
267
		fGlobalDictionaries.add(new TaskTagDictionary());
268
		fGlobalDictionaries.add(new HtmlTagDictionary());
269
		fGlobalDictionaries.add(new JavaDocTagDictionary());
270
271
		try {
272
273
			Locale locale= null;
274
			final Enumeration locations= getDictionaryLocations();
275
276
			while (locations != null && locations.hasMoreElements()) {
277
				URL location= (URL)locations.nextElement();
278
279
				for (final Iterator iterator= getLocalesWithInstalledDictionaries(location).iterator(); iterator.hasNext();) {
280
281
					locale= (Locale)iterator.next();
282
					fLocaleDictionaries.put(locale, new LocaleSensitiveSpellDictionary(locale, location));
283
				}
284
			}
285
286
		} catch (IOException exception) {
287
			// Do nothing
288
		}
289
290
		JavaPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this);
291
		EditorsUI.getPreferenceStore().addPropertyChangeListener(this);
292
	}
293
294
	/*
295
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine#getSpellChecker()
296
	 */
297
	public synchronized final ISpellChecker getSpellChecker() throws IllegalStateException {
298
		if (fGlobalDictionaries == null)
299
			throw new IllegalStateException("spell checker has been shut down"); //$NON-NLS-1$
300
301
		IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore();
302
		Locale locale= getCurrentLocale(store);
303
		if (fUserDictionary == null && "".equals(locale.toString())) //$NON-NLS-1$
304
			return null;
305
306
		if (fChecker != null && fChecker.getLocale().equals(locale))
307
			return fChecker;
308
309
		resetSpellChecker();
310
311
		fChecker= new DefaultSpellChecker(store, locale);
312
		resetUserDictionary();
313
314
		for (Iterator iterator= fGlobalDictionaries.iterator(); iterator.hasNext();) {
315
			ISpellDictionary dictionary= (ISpellDictionary)iterator.next();
316
			fChecker.addDictionary(dictionary);
317
		}
318
319
		ISpellDictionary dictionary= findDictionary(fChecker.getLocale());
320
		if (dictionary != null)
321
			fChecker.addDictionary(dictionary);
322
323
		return fChecker;
324
	}
325
326
	/**
327
	 * Returns the current locale of the spelling preferences.
328
	 *
329
	 * @param store the preference store
330
	 * @return The current locale of the spelling preferences
331
	 */
332
	private Locale getCurrentLocale(IPreferenceStore store) {
333
		return convertToLocale(store.getString(PreferenceConstants.SPELLING_LOCALE));
334
	}
335
336
	public static Locale convertToLocale(String locale) {
337
		Locale defaultLocale= SpellCheckEngine.getDefaultLocale();
338
		if (locale.equals(defaultLocale.toString()))
339
			return defaultLocale;
340
341
		int length= locale.length();
342
		if (length >= 5)
343
			return new Locale(locale.substring(0, 2), locale.substring(3, 5));
344
345
		if (length == 2 && locale.indexOf('_') == -1)
346
			return new Locale(locale);
347
348
		if (length == 3 && locale.charAt(0) == '_')
349
			return new Locale("", locale.substring(1)); //$NON-NLS-1$
350
351
		return new Locale(""); //$NON-NLS-1$
352
	}
353
354
	/*
355
	 * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellCheckEngine#getLocale()
356
	 */
357
	public synchronized final Locale getLocale() {
358
		if (fChecker == null)
359
			return null;
360
361
		return fChecker.getLocale();
362
	}
363
364
	/*
365
	 * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
366
	 */
367
	public final void propertyChange(final PropertyChangeEvent event) {
368
		if (event.getProperty().equals(PreferenceConstants.SPELLING_LOCALE)) {
369
			resetSpellChecker();
370
			return;
371
		}
372
373
		if (event.getProperty().equals(PreferenceConstants.SPELLING_USER_DICTIONARY)) {
374
			resetUserDictionary();
375
			return;
376
		}
377
378
		if (event.getProperty().equals(PreferenceConstants.SPELLING_USER_DICTIONARY_ENCODING)) {
379
			resetUserDictionary();
380
			return;
381
		}
382
383
		if (event.getProperty().equals(SpellingService.PREFERENCE_SPELLING_ENABLED) && !EditorsUI.getPreferenceStore().getBoolean(SpellingService.PREFERENCE_SPELLING_ENABLED)) {
384
			if (this == fgEngine)
385
				SpellCheckEngine.shutdownInstance();
386
			else
387
				shutdown();
388
		}
389
	}
390
391
	/**
392
	 * Resets the current checker's user dictionary.
393
	 */
394
	private synchronized void resetUserDictionary() {
395
		if (fChecker == null)
396
			return;
397
398
		// Update user dictionary
399
		if (fUserDictionary != null) {
400
			fChecker.removeDictionary(fUserDictionary);
401
			fUserDictionary.unload();
402
			fUserDictionary= null;
403
		}
404
405
		IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore();
406
		String filePath= store.getString(PreferenceConstants.SPELLING_USER_DICTIONARY);
407
408
		VariablesPlugin variablesPlugin= VariablesPlugin.getDefault();
409
		if (variablesPlugin == null)
410
			return;
411
412
		IStringVariableManager variableManager= variablesPlugin.getStringVariableManager();
413
		try {
414
			filePath= variableManager.performStringSubstitution(filePath);
415
		} catch (CoreException e) {
416
			JavaPlugin.log(e);
417
			return;
418
		}
419
		if (filePath.length() > 0) {
420
			try {
421
				File file= new File(filePath);
422
				if (!file.exists() && !file.createNewFile())
423
					return;
424
425
				final URL url= new URL("file", null, filePath); //$NON-NLS-1$
426
				InputStream stream= url.openStream();
427
				if (stream != null) {
428
					try {
429
						fUserDictionary= new PersistentSpellDictionary(url);
430
						fChecker.addDictionary(fUserDictionary);
431
					} finally {
432
						stream.close();
433
					}
434
				}
435
			} catch (MalformedURLException exception) {
436
				// Do nothing
437
			} catch (IOException exception) {
438
				// Do nothing
439
			}
440
		}
441
	}
442
443
	/*
444
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine#registerDictionary(org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary)
445
	 */
446
	public synchronized final void registerGlobalDictionary(final ISpellDictionary dictionary) {
447
		fGlobalDictionaries.add(dictionary);
448
		resetSpellChecker();
449
	}
450
451
	/*
452
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine#registerDictionary(java.util.Locale, org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary)
453
	 */
454
	public synchronized final void registerDictionary(final Locale locale, final ISpellDictionary dictionary) {
455
		fLocaleDictionaries.put(locale, dictionary);
456
		resetSpellChecker();
457
	}
458
459
	/*
460
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine#unload()
461
	 */
462
	public synchronized final void shutdown() {
463
464
		JavaPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this);
465
		EditorsUI.getPreferenceStore().removePropertyChangeListener(this);
466
467
		ISpellDictionary dictionary= null;
468
		for (final Iterator iterator= fGlobalDictionaries.iterator(); iterator.hasNext();) {
469
			dictionary= (ISpellDictionary)iterator.next();
470
			dictionary.unload();
471
		}
472
		fGlobalDictionaries= null;
473
474
		for (final Iterator iterator= fLocaleDictionaries.values().iterator(); iterator.hasNext();) {
475
			dictionary= (ISpellDictionary)iterator.next();
476
			dictionary.unload();
477
		}
478
		fLocaleDictionaries= null;
479
480
		fUserDictionary= null;
481
		fChecker= null;
482
	}
483
484
	private synchronized void resetSpellChecker() {
485
		if (fChecker != null) {
486
			ISpellDictionary dictionary= (ISpellDictionary)fLocaleDictionaries.get(fChecker.getLocale());
487
			if (dictionary != null)
488
				dictionary.unload();
489
		}
490
		fChecker= null;
491
	}
492
493
	/*
494
	 * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellCheckEngine#unregisterDictionary(org.eclipse.jdt.ui.text.spelling.engine.ISpellDictionary)
495
	 */
496
	public synchronized final void unregisterDictionary(final ISpellDictionary dictionary) {
497
		fGlobalDictionaries.remove(dictionary);
498
		fLocaleDictionaries.values().remove(dictionary);
499
		dictionary.unload();
500
		resetSpellChecker();
501
	}
502
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/SpellCheckIterator.java (-428 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.ui.text.spelling;
12
13
import java.util.LinkedList;
14
import java.util.Locale;
15
16
import com.ibm.icu.text.BreakIterator;
17
18
import org.eclipse.jface.text.IDocument;
19
import org.eclipse.jface.text.IRegion;
20
import org.eclipse.jface.text.TextUtilities;
21
22
import org.eclipse.jdt.internal.corext.refactoring.nls.NLSElement;
23
24
import org.eclipse.jdt.internal.ui.text.javadoc.IHtmlTagConstants;
25
import org.eclipse.jdt.internal.ui.text.spelling.engine.DefaultSpellChecker;
26
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckIterator;
27
28
29
/**
30
 * Iterator to spell check javadoc comment regions.
31
 *
32
 * @since 3.0
33
 */
34
public class SpellCheckIterator implements ISpellCheckIterator {
35
36
	/**
37
	 * The token that denotes whitespace.
38
	 * 
39
	 * @since 3.6
40
	 */
41
	private static final int WHITE_SPACE_TOKEN= -1;
42
43
	/** The content of the region */
44
	protected final String fContent;
45
46
	/** The line delimiter */
47
	private final String fDelimiter;
48
49
	/** The last token */
50
	protected String fLastToken= null;
51
52
	/** The next break */
53
	protected int fNext= 1;
54
55
	/** The offset of the region */
56
	protected final int fOffset;
57
58
	/** The predecessor break */
59
	private int fPredecessor;
60
61
	/** The previous break */
62
	protected int fPrevious= 0;
63
64
	/** The sentence breaks */
65
	private final LinkedList fSentenceBreaks= new LinkedList();
66
67
	/** Does the current word start a sentence? */
68
	private boolean fStartsSentence= false;
69
70
	/** The successor break */
71
	protected int fSuccessor;
72
73
	/** The word iterator */
74
	private final BreakIterator fWordIterator;
75
76
	private boolean fIsIgnoringSingleLetters;
77
78
	/**
79
	 * Creates a new spell check iterator.
80
	 *
81
	 * @param document the document containing the specified partition
82
	 * @param region the region to spell check
83
	 * @param locale the locale to use for spell checking
84
	 */
85
	public SpellCheckIterator(IDocument document, IRegion region, Locale locale) {
86
		this(document, region, locale, BreakIterator.getWordInstance(locale));
87
	}
88
89
	/**
90
	 * Creates a new spell check iterator.
91
	 *
92
	 * @param document the document containing the specified partition
93
	 * @param region the region to spell check
94
	 * @param locale the locale to use for spell checking
95
	 * @param breakIterator the break-iterator
96
	 */
97
	public SpellCheckIterator(IDocument document, IRegion region, Locale locale, BreakIterator breakIterator) {
98
		fOffset= region.getOffset();
99
		fWordIterator= breakIterator;
100
		fDelimiter= TextUtilities.getDefaultLineDelimiter(document);
101
102
		String content;
103
		try {
104
105
			content= document.get(region.getOffset(), region.getLength());
106
			if (content.startsWith(NLSElement.TAG_PREFIX))
107
				content= ""; //$NON-NLS-1$
108
109
		} catch (Exception exception) {
110
			content= ""; //$NON-NLS-1$
111
		}
112
		fContent= content;
113
114
		fWordIterator.setText(content);
115
		fPredecessor= fWordIterator.first();
116
		fSuccessor= fWordIterator.next();
117
118
		final BreakIterator iterator= BreakIterator.getSentenceInstance(locale);
119
		iterator.setText(content);
120
121
		int offset= iterator.current();
122
		while (offset != BreakIterator.DONE) {
123
124
			fSentenceBreaks.add(new Integer(offset));
125
			offset= iterator.next();
126
		}
127
	}
128
129
	/*
130
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckIterator#setIgnoreSingleLetters(boolean)
131
	 * @since 3.3
132
	 */
133
	public void setIgnoreSingleLetters(boolean state) {
134
		fIsIgnoringSingleLetters= state;
135
	}
136
137
	/*
138
	 * @see org.eclipse.spelling.done.ISpellCheckIterator#getBegin()
139
	 */
140
	public final int getBegin() {
141
		return fPrevious + fOffset;
142
	}
143
144
	/*
145
	 * @see org.eclipse.spelling.done.ISpellCheckIterator#getEnd()
146
	 */
147
	public final int getEnd() {
148
		return fNext + fOffset - 1;
149
	}
150
151
	/*
152
	 * @see java.util.Iterator#hasNext()
153
	 */
154
	public final boolean hasNext() {
155
		return fSuccessor != BreakIterator.DONE;
156
	}
157
158
	/**
159
	 * Does the specified token consist of at least one letter and digits
160
	 * only?
161
	 *
162
	 * @param begin the begin index
163
	 * @param end the end index
164
	 * @return <code>true</code> iff the token consists of digits and at
165
	 *         least one letter only, <code>false</code> otherwise
166
	 */
167
	protected final boolean isAlphaNumeric(final int begin, final int end) {
168
169
		char character= 0;
170
171
		boolean letter= false;
172
		for (int index= begin; index < end; index++) {
173
174
			character= fContent.charAt(index);
175
			if (Character.isLetter(character))
176
				letter= true;
177
178
			if (!Character.isLetterOrDigit(character))
179
				return false;
180
		}
181
		return letter;
182
	}
183
184
	/**
185
	 * Checks the last token against the given tags?
186
	 *
187
	 * @param tags the tags to check
188
	 * @return <code>true</code> iff the last token is in the given array
189
	 */
190
	protected final boolean isToken(final String[] tags) {
191
		return isToken(fLastToken, tags);
192
	}
193
194
	/**
195
	 * Checks the given  token against the given tags?
196
	 *
197
	 * @param token the token to check
198
	 * @param tags the tags to check
199
	 * @return <code>true</code> iff the last token is in the given array
200
	 * @since 3.3
201
	 */
202
	protected final boolean isToken(final String token, final String[] tags) {
203
204
		if (token != null) {
205
206
			for (int index= 0; index < tags.length; index++) {
207
208
				if (token.equals(tags[index]))
209
					return true;
210
			}
211
		}
212
		return false;
213
	}
214
215
	/**
216
	 * Is the current token a single letter token surrounded by
217
	 * non-whitespace characters?
218
	 *
219
	 * @param begin the begin index
220
	 * @return <code>true</code> iff the token is a single letter token,
221
	 *         <code>false</code> otherwise
222
	 */
223
	protected final boolean isSingleLetter(final int begin) {
224
		if (!Character.isLetter(fContent.charAt(begin)))
225
			return false;
226
227
		if (begin > 0 && !Character.isWhitespace(fContent.charAt(begin - 1)))
228
			return false;
229
230
		if (begin < fContent.length() - 1 && !Character.isWhitespace(fContent.charAt(begin + 1)))
231
			return false;
232
233
		return true;
234
	}
235
236
	/**
237
	 * Does the specified token look like an URL?
238
	 *
239
	 * @param begin the begin index
240
	 * @return <code>true</code> iff this token look like an URL,
241
	 *         <code>false</code> otherwise
242
	 */
243
	protected final boolean isUrlToken(final int begin) {
244
245
		for (int index= 0; index < DefaultSpellChecker.URL_PREFIXES.length; index++) {
246
247
			if (fContent.startsWith(DefaultSpellChecker.URL_PREFIXES[index], begin))
248
				return true;
249
		}
250
		return false;
251
	}
252
253
	/**
254
	 * Does the specified token consist of whitespace only?
255
	 *
256
	 * @param begin the begin index
257
	 * @param end the end index
258
	 * @return <code>true</code> iff the token consists of whitespace
259
	 *         only, <code>false</code> otherwise
260
	 */
261
	protected final boolean isWhitespace(final int begin, final int end) {
262
263
		for (int index= begin; index < end; index++) {
264
265
			if (!Character.isWhitespace(fContent.charAt(index)))
266
				return false;
267
		}
268
		return true;
269
	}
270
271
	/*
272
	 * @see java.util.Iterator#next()
273
	 */
274
	public Object next() {
275
276
		String token= nextToken();
277
		while (token == null && fSuccessor != BreakIterator.DONE)
278
			token= nextToken();
279
280
		fLastToken= token;
281
282
		return token;
283
	}
284
285
	/**
286
	 * Advances the end index to the next word break.
287
	 */
288
	protected final void nextBreak() {
289
290
		fNext= fSuccessor;
291
		fPredecessor= fSuccessor;
292
293
		fSuccessor= fWordIterator.next();
294
	}
295
296
	/**
297
	 * Returns the next sentence break.
298
	 *
299
	 * @return the next sentence break
300
	 */
301
	protected final int nextSentence() {
302
		return ((Integer) fSentenceBreaks.getFirst()).intValue();
303
	}
304
305
	/**
306
	 * Determines the next token to be spell checked.
307
	 *
308
	 * @return the next token to be spell checked, or <code>null</code>
309
	 *         iff the next token is not a candidate for spell checking.
310
	 */
311
	protected String nextToken() {
312
313
		String token= null;
314
315
		fPrevious= fPredecessor;
316
		fStartsSentence= false;
317
318
		nextBreak();
319
320
		boolean update= false;
321
		if (fNext - fPrevious > 0) {
322
323
			if (fSuccessor != BreakIterator.DONE && fContent.charAt(fPrevious) == IJavaDocTagConstants.JAVADOC_TAG_PREFIX) {
324
325
				nextBreak();
326
				if (Character.isLetter(fContent.charAt(fPrevious + 1))) {
327
					update= true;
328
					token= fContent.substring(fPrevious, fNext);
329
				} else
330
					fPredecessor= fNext;
331
332
			} else if (fSuccessor != BreakIterator.DONE && fContent.charAt(fPrevious) == IHtmlTagConstants.HTML_TAG_PREFIX && (Character.isLetter(fContent.charAt(fNext)) || fContent.charAt(fNext) == '/')) {
333
334
				if (fContent.startsWith(IHtmlTagConstants.HTML_CLOSE_PREFIX, fPrevious))
335
					nextBreak();
336
337
				nextBreak();
338
339
				if (fSuccessor != BreakIterator.DONE && fContent.charAt(fNext) == IHtmlTagConstants.HTML_TAG_POSTFIX) {
340
341
					nextBreak();
342
					if (fSuccessor != BreakIterator.DONE) {
343
						update= true;
344
						token= fContent.substring(fPrevious, fNext);
345
					}
346
				}
347
			} else if (fSuccessor != BreakIterator.DONE && fContent.charAt(fPrevious) == IHtmlTagConstants.HTML_ENTITY_START && (Character.isLetter(fContent.charAt(fNext)))) {
348
				nextBreak();
349
				if (fSuccessor != BreakIterator.DONE && fContent.charAt(fNext) == IHtmlTagConstants.HTML_ENTITY_END) {
350
					nextBreak();
351
					if (isToken(fContent.substring(fPrevious, fNext), IHtmlTagConstants.HTML_ENTITY_CODES)) {
352
						skipTokens(fPrevious, IHtmlTagConstants.HTML_ENTITY_END);
353
						update= true;
354
					} else
355
						token= fContent.substring(fPrevious, fNext);
356
				} else
357
					token= fContent.substring(fPrevious, fNext);
358
359
				update= true;
360
			} else if (!isWhitespace(fPrevious, fNext) && isAlphaNumeric(fPrevious, fNext)) {
361
362
				if (isUrlToken(fPrevious))
363
					skipTokens(fPrevious, WHITE_SPACE_TOKEN);
364
				else if (isToken(IJavaDocTagConstants.JAVADOC_PARAM_TAGS))
365
					fLastToken= null;
366
				else if (isToken(IJavaDocTagConstants.JAVADOC_REFERENCE_TAGS)) {
367
					fLastToken= null;
368
					skipTokens(fPrevious, fDelimiter.charAt(0));
369
				} else if (fNext - fPrevious > 1 || isSingleLetter(fPrevious) && !fIsIgnoringSingleLetters)
370
					token= fContent.substring(fPrevious, fNext);
371
372
				update= true;
373
			}
374
		}
375
376
		if (update && fSentenceBreaks.size() > 0) {
377
378
			if (fPrevious >= nextSentence()) {
379
380
				while (fSentenceBreaks.size() > 0 && fPrevious >= nextSentence())
381
					fSentenceBreaks.removeFirst();
382
383
				fStartsSentence= (fLastToken == null) || (token != null);
384
			}
385
		}
386
		return token;
387
	}
388
389
	/*
390
	 * @see java.util.Iterator#remove()
391
	 */
392
	public final void remove() {
393
		throw new UnsupportedOperationException();
394
	}
395
396
	/**
397
	 * Skip the tokens until the stop character is reached.
398
	 *
399
	 * @param begin the begin index
400
	 * @param stop the stop character
401
	 */
402
	protected final void skipTokens(final int begin, final int stop) {
403
		final boolean isStoppingOnWhiteSpace= stop == WHITE_SPACE_TOKEN;
404
		int end= begin;
405
		while (end < fContent.length()) {
406
			char ch= fContent.charAt(end);
407
			if (ch == stop || isStoppingOnWhiteSpace && Character.isWhitespace(ch))
408
				break;
409
			end++;
410
		}
411
412
		if (end < fContent.length()) {
413
414
			fNext= end;
415
			fPredecessor= fNext;
416
417
			fSuccessor= fWordIterator.following(fNext);
418
		} else
419
			fSuccessor= BreakIterator.DONE;
420
	}
421
422
	/*
423
	 * @see org.eclipse.spelling.done.ISpellCheckIterator#startsSentence()
424
	 */
425
	public final boolean startsSentence() {
426
		return fStartsSentence;
427
	}
428
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/SpellingEngine.java (-105 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.ui.text.spelling;
12
13
import org.eclipse.core.runtime.IProgressMonitor;
14
15
import org.eclipse.jface.text.IDocument;
16
import org.eclipse.jface.text.IRegion;
17
18
import org.eclipse.ui.texteditor.spelling.ISpellingEngine;
19
import org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector;
20
import org.eclipse.ui.texteditor.spelling.SpellingContext;
21
22
import org.eclipse.jdt.ui.PreferenceConstants;
23
24
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine;
25
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker;
26
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEvent;
27
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEventListener;
28
29
30
/**
31
 * Internal abstract spelling engine, subclasses provide a content-type specific implementation.
32
 *
33
 * @since 3.1
34
 */
35
public abstract class SpellingEngine implements ISpellingEngine {
36
37
	/**
38
	 * {@link ISpellEvent}listener that forwards events as
39
	 * {@link org.eclipse.ui.texteditor.spelling.SpellingProblem}.
40
	 */
41
	protected static class SpellEventListener implements ISpellEventListener {
42
43
		/** Spelling problem collector */
44
		private ISpellingProblemCollector fCollector;
45
46
		/**
47
		 * The document.
48
		 * @since 3.3
49
		 */
50
		private IDocument fDocument;
51
52
		private int fProblemsThreshold;
53
		private int fProblemCount;
54
55
		/**
56
		 * Initialize with the given spelling problem collector.
57
		 *
58
		 * @param collector the spelling problem collector
59
		 * @param document the document
60
		 */
61
		public SpellEventListener(ISpellingProblemCollector collector, IDocument document) {
62
			fCollector= collector;
63
			fDocument= document;
64
			fProblemsThreshold= PreferenceConstants.getPreferenceStore().getInt(PreferenceConstants.SPELLING_PROBLEMS_THRESHOLD);
65
		}
66
67
		/*
68
		 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEventListener#handle(org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEvent)
69
		 */
70
		public void handle(ISpellEvent event) {
71
			if (isProblemsThresholdReached())
72
				return;
73
			fProblemCount++;
74
			fCollector.accept(new JavaSpellingProblem(event, fDocument));
75
		}
76
77
		boolean isProblemsThresholdReached() {
78
			return fProblemCount >= fProblemsThreshold;
79
		}
80
	}
81
82
	/*
83
	 * @see org.eclipse.ui.texteditor.spelling.ISpellingEngine#check(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IRegion[], org.eclipse.ui.texteditor.spelling.SpellingContext, org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector, org.eclipse.core.runtime.IProgressMonitor)
84
	 */
85
	public void check(IDocument document, IRegion[] regions, SpellingContext context, ISpellingProblemCollector collector, IProgressMonitor monitor) {
86
		if (collector != null) {
87
			final ISpellCheckEngine spellingEngine= SpellCheckEngine.getInstance();
88
			ISpellChecker checker= spellingEngine.getSpellChecker();
89
			if (checker != null)
90
				check(document, regions, checker, collector, monitor);
91
		}
92
	}
93
94
	/**
95
	 * Spell checks the given document regions with the given arguments.
96
	 *
97
	 * @param document the document
98
	 * @param regions the regions
99
	 * @param checker the spell checker
100
	 * @param collector the spelling problem collector
101
	 * @param monitor the progress monitor, can be <code>null</code>
102
	 */
103
	protected abstract void check(IDocument document, IRegion[] regions, ISpellChecker checker, ISpellingProblemCollector collector, IProgressMonitor monitor);
104
105
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/TaskTagDictionary.java (-2 / +4 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 18-26 Link Here
18
import org.eclipse.core.runtime.Preferences.IPropertyChangeListener;
18
import org.eclipse.core.runtime.Preferences.IPropertyChangeListener;
19
import org.eclipse.core.runtime.Preferences.PropertyChangeEvent;
19
import org.eclipse.core.runtime.Preferences.PropertyChangeEvent;
20
20
21
import org.eclipse.ui.texteditor.spelling.engine.AbstractSpellDictionary;
22
23
21
import org.eclipse.jdt.core.JavaCore;
24
import org.eclipse.jdt.core.JavaCore;
22
25
23
import org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary;
24
26
25
/**
27
/**
26
 * Dictionary for task tags.
28
 * Dictionary for task tags.
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/TextSpellingEngine.java (-43 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling;
13
14
import org.eclipse.core.runtime.IProgressMonitor;
15
16
import org.eclipse.jface.text.IDocument;
17
import org.eclipse.jface.text.IRegion;
18
19
import org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector;
20
21
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker;
22
23
/**
24
 * Text spelling engine
25
 *
26
 * @since 3.1
27
 */
28
public class TextSpellingEngine extends SpellingEngine {
29
30
	/*
31
	 * @see org.eclipse.jdt.internal.ui.text.spelling.SpellingEngine#check(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IRegion[], org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker, org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector, org.eclipse.core.runtime.IProgressMonitor)
32
	 */
33
	protected void check(IDocument document, IRegion[] regions, ISpellChecker checker, ISpellingProblemCollector collector, IProgressMonitor monitor) {
34
		SpellEventListener listener= new SpellEventListener(collector, document);
35
		for (int i= 0; i < regions.length; i++) {
36
			if (monitor != null && monitor.isCanceled())
37
				return;
38
			if (listener.isProblemsThresholdReached())
39
				return;
40
			checker.execute(listener, new SpellCheckIterator(document, regions[i], checker.getLocale()));
41
		}
42
	}
43
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/WordCompletionProposalComputer.java (-139 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling;
13
14
import java.util.ArrayList;
15
import java.util.Collections;
16
import java.util.Iterator;
17
import java.util.List;
18
19
import org.eclipse.core.runtime.IProgressMonitor;
20
21
import org.eclipse.jface.text.BadLocationException;
22
import org.eclipse.jface.text.DocumentEvent;
23
import org.eclipse.jface.text.IDocument;
24
import org.eclipse.jface.text.IRegion;
25
26
import org.eclipse.jdt.ui.PreferenceConstants;
27
import org.eclipse.jdt.ui.text.java.ContentAssistInvocationContext;
28
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposalComputer;
29
30
import org.eclipse.jdt.internal.ui.JavaPlugin;
31
import org.eclipse.jdt.internal.ui.JavaPluginImages;
32
import org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposal;
33
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine;
34
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker;
35
import org.eclipse.jdt.internal.ui.text.spelling.engine.RankedWordProposal;
36
37
/**
38
 * Content assist processor to complete words.
39
 * <strong>Note:</strong> This is currently not supported because the spelling engine
40
 * cannot return word proposals but only correction proposals.
41
 * <p>
42
 * If we enable this again we must register the computer in <code>plugin.xml</code>:
43
 * <pre>
44
 * </pre>
45
 * </p>
46
 *
47
 * @since 3.0
48
 */
49
public final class WordCompletionProposalComputer implements IJavaCompletionProposalComputer {
50
51
	/** The prefix rank shift */
52
	private static final int PREFIX_RANK_SHIFT= 500;
53
54
	/*
55
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposalComputer#computeCompletionProposals(org.eclipse.jface.text.contentassist.TextContentAssistInvocationContext, org.eclipse.core.runtime.IProgressMonitor)
56
	 */
57
	public List computeCompletionProposals(ContentAssistInvocationContext context, IProgressMonitor monitor) {
58
		if (contributes()) {
59
			try {
60
				IDocument document= context.getDocument();
61
				final int offset= context.getInvocationOffset();
62
63
				final IRegion region= document.getLineInformationOfOffset(offset);
64
				final String content= document.get(region.getOffset(), region.getLength());
65
66
				int index= offset - region.getOffset() - 1;
67
				while (index >= 0 && Character.isLetter(content.charAt(index)))
68
					index--;
69
70
				final int start= region.getOffset() + index + 1;
71
				final String candidate= content.substring(index + 1, offset - region.getOffset());
72
73
				if (candidate.length() > 0) {
74
75
					final ISpellCheckEngine engine= SpellCheckEngine.getInstance();
76
					final ISpellChecker checker= engine.getSpellChecker();
77
78
					if (checker != null) {
79
80
						final List proposals= new ArrayList(checker.getProposals(candidate, Character.isUpperCase(candidate.charAt(0))));
81
						final List result= new ArrayList(proposals.size());
82
83
						for (Iterator it= proposals.iterator(); it.hasNext();) {
84
							RankedWordProposal word= (RankedWordProposal) it.next();
85
							String text= word.getText();
86
							if (text.startsWith(candidate))
87
								word.setRank(word.getRank() + PREFIX_RANK_SHIFT);
88
89
							result.add(new JavaCompletionProposal(text, start, candidate.length(), JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_RENAME), text, word.getRank()) {
90
								/*
91
								 * @see org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposal#validate(org.eclipse.jface.text.IDocument, int, org.eclipse.jface.text.DocumentEvent)
92
								 */
93
								public boolean validate(IDocument doc, int validate_offset, DocumentEvent event) {
94
									return offset == validate_offset;
95
								}
96
							});
97
						}
98
99
						return result;
100
					}
101
				}
102
			} catch (BadLocationException exception) {
103
				// log & ignore
104
				JavaPlugin.log(exception);
105
			}
106
		}
107
		return Collections.EMPTY_LIST;
108
	}
109
110
	private boolean contributes() {
111
		return PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.SPELLING_ENABLE_CONTENTASSIST);
112
	}
113
114
	/*
115
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposalComputer#computeContextInformation(org.eclipse.jface.text.contentassist.TextContentAssistInvocationContext, org.eclipse.core.runtime.IProgressMonitor)
116
	 */
117
	public List computeContextInformation(ContentAssistInvocationContext context, IProgressMonitor monitor) {
118
		return Collections.EMPTY_LIST;
119
	}
120
121
	/*
122
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposalComputer#getErrorMessage()
123
	 */
124
	public String getErrorMessage() {
125
		return null; // no error message available
126
	}
127
128
	/*
129
	 * @see org.eclipse.jdt.ui.text.java.IJavaCompletionProposalComputer#sessionStarted()
130
	 */
131
	public void sessionStarted() {
132
	}
133
134
	/*
135
	 * @see org.eclipse.jdt.ui.text.java.IJavaCompletionProposalComputer#sessionEnded()
136
	 */
137
	public void sessionEnded() {
138
	}
139
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/WordCorrectionProposal.java (-178 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2009 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling;
13
14
import org.eclipse.swt.graphics.Image;
15
import org.eclipse.swt.graphics.Point;
16
17
import org.eclipse.jface.text.BadLocationException;
18
import org.eclipse.jface.text.IDocument;
19
import org.eclipse.jface.text.contentassist.IContextInformation;
20
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
21
22
import org.eclipse.jdt.internal.corext.util.Messages;
23
24
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
25
26
import org.eclipse.jdt.internal.ui.JavaPluginImages;
27
import org.eclipse.jdt.internal.ui.JavaUIMessages;
28
import org.eclipse.jdt.internal.ui.text.javadoc.IHtmlTagConstants;
29
30
/**
31
 * Proposal to correct the incorrectly spelled word.
32
 *
33
 * @since 3.0
34
 */
35
public class WordCorrectionProposal implements IJavaCompletionProposal {
36
37
	/**
38
	 * Returns the html representation of the specified string.
39
	 *
40
	 * @param string
41
	 *                   The string to return the html representation for
42
	 * @return The html representation for the string
43
	 */
44
	public static String getHtmlRepresentation(final String string) {
45
46
		final int length= string.length();
47
		final StringBuffer buffer= new StringBuffer(string);
48
49
		for (int offset= length - 1; offset >= 0; offset--) {
50
51
			for (int index= 0; index < IHtmlTagConstants.HTML_ENTITY_CHARACTERS.length; index++) {
52
53
				if (string.charAt(offset) == IHtmlTagConstants.HTML_ENTITY_CHARACTERS[index]) {
54
55
					buffer.replace(offset, offset + 1, String.valueOf(IHtmlTagConstants.HTML_ENTITY_CODES[index]));
56
					break;
57
				}
58
			}
59
		}
60
		return buffer.toString();
61
	}
62
63
	/** The invocation context */
64
	private final IQuickAssistInvocationContext fContext;
65
66
	/** The length in the document */
67
	private final int fLength;
68
69
	/** The line where to apply the correction */
70
	private final String fLine;
71
72
	/** The offset in the document */
73
	private final int fOffset;
74
75
	/** The relevance of this proposal */
76
	private final int fRelevance;
77
78
	/** The word to complete */
79
	private final String fWord;
80
81
	/**
82
	 * Creates a new word correction proposal.
83
	 *
84
	 * @param word the corrected word
85
	 * @param arguments the problem arguments associated with the spelling problem
86
	 * @param offset the offset in the document where to apply the proposal
87
	 * @param length the lenght in the document to apply the proposal
88
	 * @param context the invocation context for this proposal
89
	 * @param relevance the relevance of this proposal
90
	 */
91
	public WordCorrectionProposal(final String word, final String[] arguments, final int offset, final int length, final IQuickAssistInvocationContext context, final int relevance) {
92
93
		fWord= Character.isUpperCase(arguments[0].charAt(0)) ? Character.toUpperCase(word.charAt(0)) + word.substring(1) : word;
94
95
		fOffset= offset;
96
		fLength= length;
97
		fContext= context;
98
		fRelevance= relevance;
99
100
		final StringBuffer buffer= new StringBuffer(80);
101
102
		buffer.append("...<br>"); //$NON-NLS-1$
103
		buffer.append(getHtmlRepresentation(arguments[1]));
104
		buffer.append("<b>"); //$NON-NLS-1$
105
		buffer.append(getHtmlRepresentation(fWord));
106
		buffer.append("</b>"); //$NON-NLS-1$
107
		buffer.append(getHtmlRepresentation(arguments[2]));
108
		buffer.append("<br>..."); //$NON-NLS-1$
109
110
		fLine= buffer.toString();
111
	}
112
113
	/*
114
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(org.eclipse.jface.text.IDocument)
115
	 */
116
	public final void apply(final IDocument document) {
117
		try {
118
			document.replace(fOffset, fLength, fWord);
119
		} catch (BadLocationException exception) {
120
			// Do nothing
121
		}
122
	}
123
124
	/*
125
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo()
126
	 */
127
	public String getAdditionalProposalInfo() {
128
		return fLine;
129
	}
130
131
	/*
132
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getContextInformation()
133
	 */
134
	public final IContextInformation getContextInformation() {
135
		return null;
136
	}
137
138
	/*
139
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString()
140
	 */
141
	public String getDisplayString() {
142
		return Messages.format(JavaUIMessages.Spelling_correct_label, new String[] { fWord });
143
	}
144
145
	/*
146
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage()
147
	 */
148
	public Image getImage() {
149
		return JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_RENAME);
150
	}
151
152
	/*
153
	 * @see org.eclipse.jdt.ui.text.java.IJavaCompletionProposal#getRelevance()
154
	 */
155
	public final int getRelevance() {
156
		return fRelevance;
157
	}
158
159
	/*
160
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getSelection(org.eclipse.jface.text.IDocument)
161
	 */
162
	public final Point getSelection(final IDocument document) {
163
164
		int offset= fContext.getOffset();
165
		int length= fContext.getLength();
166
167
		final int delta= fWord.length() - fLength;
168
		if (offset <= fOffset && offset + length >= fOffset)
169
			length += delta;
170
		else if (offset > fOffset && offset + length > fOffset + fLength) {
171
			offset += delta;
172
			length -= delta;
173
		} else
174
			length += delta;
175
176
		return new Point(offset, length);
177
	}
178
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/WordIgnoreProposal.java (-115 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2009 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling;
13
14
import org.eclipse.swt.graphics.Image;
15
import org.eclipse.swt.graphics.Point;
16
17
import org.eclipse.jface.text.IDocument;
18
import org.eclipse.jface.text.contentassist.IContextInformation;
19
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
20
import org.eclipse.jface.text.source.ISourceViewer;
21
22
import org.eclipse.ui.texteditor.spelling.SpellingProblem;
23
24
import org.eclipse.jdt.internal.corext.util.Messages;
25
26
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
27
28
import org.eclipse.jdt.internal.ui.JavaPluginImages;
29
import org.eclipse.jdt.internal.ui.JavaUIMessages;
30
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine;
31
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker;
32
33
/**
34
 * Proposal to ignore the word during the current editing session.
35
 *
36
 * @since 3.0
37
 */
38
public class WordIgnoreProposal implements IJavaCompletionProposal {
39
40
	/** The invocation context */
41
	private IQuickAssistInvocationContext fContext;
42
43
	/** The word to ignore */
44
	private String fWord;
45
46
	/**
47
	 * Creates a new spell ignore proposal.
48
	 *
49
	 * @param word
50
	 *                   The word to ignore
51
	 * @param context
52
	 *                   The invocation context
53
	 */
54
	public WordIgnoreProposal(final String word, final IQuickAssistInvocationContext context) {
55
		fWord= word;
56
		fContext= context;
57
	}
58
59
	/*
60
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(org.eclipse.jface.text.IDocument)
61
	 */
62
	public final void apply(final IDocument document) {
63
64
		final ISpellCheckEngine engine= SpellCheckEngine.getInstance();
65
		final ISpellChecker checker= engine.getSpellChecker();
66
67
		if (checker != null) {
68
			checker.ignoreWord(fWord);
69
			ISourceViewer sourceViewer= fContext.getSourceViewer();
70
			if (sourceViewer != null)
71
				SpellingProblem.removeAll(sourceViewer, fWord);
72
		}
73
	}
74
75
	/*
76
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo()
77
	 */
78
	public String getAdditionalProposalInfo() {
79
		return Messages.format(JavaUIMessages.Spelling_ignore_info, new String[] { WordCorrectionProposal.getHtmlRepresentation(fWord)});
80
	}
81
82
	/*
83
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getContextInformation()
84
	 */
85
	public final IContextInformation getContextInformation() {
86
		return null;
87
	}
88
89
	/*
90
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString()
91
	 */
92
	public String getDisplayString() {
93
		return Messages.format(JavaUIMessages.Spelling_ignore_label, new String[] { fWord });
94
	}
95
96
	/*
97
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage()
98
	 */
99
	public Image getImage() {
100
		return JavaPluginImages.get(JavaPluginImages.IMG_OBJS_NLS_NEVER_TRANSLATE);
101
	}
102
	/*
103
	 * @see org.eclipse.jdt.ui.text.java.IJavaCompletionProposal#getRelevance()
104
	 */
105
	public final int getRelevance() {
106
		return Integer.MIN_VALUE + 1;
107
	}
108
109
	/*
110
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getSelection(org.eclipse.jface.text.IDocument)
111
	 */
112
	public final Point getSelection(final IDocument document) {
113
		return new Point(fContext.getOffset(), fContext.getLength());
114
	}
115
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/WordQuickFixProcessor.java (-134 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2009 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.ui.text.spelling;
12
13
import java.util.ArrayList;
14
import java.util.Collections;
15
import java.util.List;
16
17
import org.eclipse.core.runtime.CoreException;
18
19
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
20
import org.eclipse.jface.text.source.ISourceViewer;
21
import org.eclipse.jface.text.source.TextInvocationContext;
22
23
import org.eclipse.jdt.core.ICompilationUnit;
24
25
import org.eclipse.jdt.ui.PreferenceConstants;
26
import org.eclipse.jdt.ui.text.java.IInvocationContext;
27
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
28
import org.eclipse.jdt.ui.text.java.IProblemLocation;
29
import org.eclipse.jdt.ui.text.java.IQuickFixProcessor;
30
31
import org.eclipse.jdt.internal.ui.text.javadoc.IHtmlTagConstants;
32
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine;
33
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker;
34
import org.eclipse.jdt.internal.ui.text.spelling.engine.RankedWordProposal;
35
36
/**
37
 * Quick fix processor for incorrectly spelled words.
38
 *
39
 * @since 3.0
40
 */
41
public class WordQuickFixProcessor implements IQuickFixProcessor {
42
43
	/**
44
	 * Creates a new word quick fix processor.
45
	 */
46
	public WordQuickFixProcessor() {
47
		// For extension point
48
	}
49
50
	/*
51
	 * @see org.eclipse.jdt.ui.text.java.IQuickFixProcessor#getCorrections(org.eclipse.jdt.ui.text.java.IInvocationContext,org.eclipse.jdt.ui.text.java.IProblemLocation[])
52
	 */
53
	public IJavaCompletionProposal[] getCorrections(IInvocationContext invocationContext, IProblemLocation[] locations) throws CoreException {
54
55
		final int threshold= PreferenceConstants.getPreferenceStore().getInt(PreferenceConstants.SPELLING_PROPOSAL_THRESHOLD);
56
57
		int size= 0;
58
		List proposals= null;
59
		String[] arguments= null;
60
61
		IProblemLocation location= null;
62
		RankedWordProposal proposal= null;
63
		IJavaCompletionProposal[] result= null;
64
65
		boolean fixed= false;
66
		boolean match= false;
67
		boolean sentence= false;
68
69
		final ISpellCheckEngine engine= SpellCheckEngine.getInstance();
70
		final ISpellChecker checker= engine.getSpellChecker();
71
72
		if (checker != null) {
73
74
			for (int index= 0; index < locations.length; index++) {
75
				location= locations[index];
76
				
77
				ISourceViewer sourceViewer= null;
78
				if (invocationContext instanceof IQuickAssistInvocationContext)
79
					sourceViewer= ((IQuickAssistInvocationContext)invocationContext).getSourceViewer();
80
				IQuickAssistInvocationContext context= new TextInvocationContext(sourceViewer, location.getOffset(), location.getLength());
81
				
82
				if (location.getProblemId() == JavaSpellingReconcileStrategy.SPELLING_PROBLEM_ID) {
83
84
					arguments= location.getProblemArguments();
85
					if (arguments != null && arguments.length > 4) {
86
87
						sentence= Boolean.valueOf(arguments[3]).booleanValue();
88
						match= Boolean.valueOf(arguments[4]).booleanValue();
89
						fixed= arguments[0].charAt(0) == IHtmlTagConstants.HTML_TAG_PREFIX || arguments[0].charAt(0) == IJavaDocTagConstants.JAVADOC_TAG_PREFIX;
90
91
						if ((sentence && match) && !fixed)
92
							result= new IJavaCompletionProposal[] { new ChangeCaseProposal(arguments, location.getOffset(), location.getLength(), context, engine.getLocale())};
93
						else {
94
95
							proposals= new ArrayList(checker.getProposals(arguments[0], sentence));
96
							size= proposals.size();
97
98
							if (threshold > 0 && size > threshold) {
99
100
								Collections.sort(proposals);
101
								proposals= proposals.subList(size - threshold - 1, size - 1);
102
								size= proposals.size();
103
							}
104
105
							boolean extendable= !fixed ? (checker.acceptsWords() || AddWordProposal.canAskToConfigure()) : false;
106
							result= new IJavaCompletionProposal[size + (extendable ? 3 : 2)];
107
108
							for (index= 0; index < size; index++) {
109
110
								proposal= (RankedWordProposal)proposals.get(index);
111
								result[index]= new WordCorrectionProposal(proposal.getText(), arguments, location.getOffset(), location.getLength(), context, proposal.getRank());
112
							}
113
114
							if (extendable)
115
								result[index++]= new AddWordProposal(arguments[0], context);
116
117
							result[index++]= new WordIgnoreProposal(arguments[0], context);
118
							result[index++]= new DisableSpellCheckingProposal(context);
119
						}
120
						break;
121
					}
122
				}
123
			}
124
		}
125
		return result;
126
	}
127
128
	/*
129
	 * @see org.eclipse.jdt.ui.text.java.IQuickFixProcessor#hasCorrections(org.eclipse.jdt.core.ICompilationUnit,int)
130
	 */
131
	public final boolean hasCorrections(ICompilationUnit unit, int id) {
132
		return id == JavaSpellingReconcileStrategy.SPELLING_PROBLEM_ID;
133
	}
134
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/engine/AbstractSpellDictionary.java (-745 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.ui.text.spelling.engine;
12
13
import java.io.BufferedReader;
14
import java.io.FileNotFoundException;
15
import java.io.IOException;
16
import java.io.InputStream;
17
import java.io.InputStreamReader;
18
import java.io.UnsupportedEncodingException;
19
import java.net.MalformedURLException;
20
import java.net.URL;
21
import java.nio.charset.Charset;
22
import java.nio.charset.CharsetDecoder;
23
import java.nio.charset.CodingErrorAction;
24
import java.nio.charset.MalformedInputException;
25
import java.util.ArrayList;
26
import java.util.Arrays;
27
import java.util.HashMap;
28
import java.util.HashSet;
29
import java.util.Iterator;
30
import java.util.Map;
31
import java.util.Set;
32
33
import org.eclipse.core.runtime.IStatus;
34
import org.eclipse.core.runtime.Status;
35
36
import org.eclipse.core.resources.ResourcesPlugin;
37
38
import org.eclipse.jdt.internal.corext.util.Messages;
39
40
import org.eclipse.jdt.ui.JavaUI;
41
import org.eclipse.jdt.ui.PreferenceConstants;
42
43
import org.eclipse.jdt.internal.ui.JavaPlugin;
44
import org.eclipse.jdt.internal.ui.JavaUIMessages;
45
import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
46
47
48
/**
49
 * Partial implementation of a spell dictionary.
50
 *
51
 * @since 3.0
52
 */
53
public abstract class AbstractSpellDictionary implements ISpellDictionary {
54
55
	/**
56
	 * Byte array wrapper
57
	 * @since 3.6
58
	 */
59
	private static class ByteArrayWrapper {
60
61
		private static int hashCode(byte[] array) {
62
			int prime= 31;
63
			if (array == null)
64
				return 0;
65
			int result= 1;
66
			for (int index= 0; index < array.length; index++) {
67
				result= prime * result + array[index];
68
			}
69
			return result;
70
		}
71
72
		private byte[] byteArray;
73
74
		public ByteArrayWrapper(byte[] byteArray) {
75
			this.byteArray= byteArray;
76
		}
77
		public int hashCode() {
78
			final int prime= 31;
79
			int result= 1;
80
			result= prime * result + ByteArrayWrapper.hashCode(byteArray);
81
			return result;
82
		}
83
84
		public boolean equals(Object obj) {
85
			if (this == obj)
86
				return true;
87
			if (obj == null)
88
				return false;
89
			if (!(obj instanceof ByteArrayWrapper))
90
				return false;
91
			ByteArrayWrapper other= (ByteArrayWrapper)obj;
92
			if (!Arrays.equals(byteArray, other.byteArray))
93
				return false;
94
			return true;
95
		}
96
	}
97
98
	
99
	/**
100
	 * Canonical name for UTF-8 encoding
101
	 * @since 3.6
102
	 */
103
	private static final String UTF_8= "UTF-8"; //$NON-NLS-1$
104
105
	/** The bucket capacity */
106
	protected static final int BUCKET_CAPACITY= 4;
107
108
	/** The word buffer capacity */
109
	protected static final int BUFFER_CAPACITY= 32;
110
111
	/** The distance threshold */
112
	protected static final int DISTANCE_THRESHOLD= 160;
113
114
	/**
115
	 * The hash load factor
116
	 * @since 3.6
117
	 */
118
	protected static final float LOAD_FACTOR= 0.85f;
119
120
	/** The phonetic distance algorithm */
121
	private IPhoneticDistanceAlgorithm fDistanceAlgorithm= new DefaultPhoneticDistanceAlgorithm();
122
123
	/** The mapping from phonetic hashes to word lists */
124
	private final Map fHashBuckets= new HashMap(getInitialSize(), LOAD_FACTOR);
125
126
	/** The phonetic hash provider */
127
	private IPhoneticHashProvider fHashProvider= new DefaultPhoneticHashProvider();
128
129
	/** Is the dictionary already loaded? */
130
	private boolean fLoaded= false;
131
	/**
132
	 * Must the dictionary be loaded?
133
	 * @since 3.2
134
	 */
135
	private boolean fMustLoad= true;
136
137
	/**
138
	 * Tells whether to strip non-letters at word boundaries.
139
	 * @since 3.3
140
	 */
141
	boolean fIsStrippingNonLetters= true;
142
143
	/**
144
	 * Returns the initial size of dictionary.
145
	 * 
146
	 * @return The initial size of dictionary.
147
	 * @since 3.6
148
	 */
149
	protected int getInitialSize() {
150
		return 32;
151
	}
152
153
	/**
154
	 * Returns all candidates with the same phonetic hash.
155
	 *
156
	 * @param hash
157
	 *                   The hash to retrieve the candidates of
158
	 * @return Array of candidates for the phonetic hash
159
	 */
160
	protected final Object getCandidates(final String hash) {
161
		ByteArrayWrapper hashBytes;
162
		try {
163
			hashBytes= new ByteArrayWrapper(hash.getBytes(UTF_8));
164
		} catch (UnsupportedEncodingException e) {
165
			JavaPlugin.log(e);
166
			return null;
167
		}
168
		return fHashBuckets.get(hashBytes);
169
	}
170
171
	/**
172
	 * Returns all candidates that have a phonetic hash within a bounded
173
	 * distance to the specified word.
174
	 *
175
	 * @param word
176
	 *                   The word to find the nearest matches for
177
	 * @param sentence
178
	 *                   <code>true</code> iff the proposals start a new sentence,
179
	 *                   <code>false</code> otherwise
180
	 * @param hashs
181
	 *                   Array of close hashes to find the matches
182
	 * @return Set of ranked words with bounded distance to the specified word
183
	 */
184
	protected final Set getCandidates(final String word, final boolean sentence, final ArrayList hashs) {
185
186
		int distance= 0;
187
		String hash= null;
188
189
		final StringBuffer buffer= new StringBuffer(BUFFER_CAPACITY);
190
		final HashSet result= new HashSet(BUCKET_CAPACITY * hashs.size());
191
192
		for (int index= 0; index < hashs.size(); index++) {
193
194
			hash= (String)hashs.get(index);
195
196
			final Object candidates= getCandidates(hash);
197
			if (candidates == null)
198
				continue;
199
			else if (candidates instanceof byte[]) {
200
				String candidate;
201
				try {
202
					candidate= new String((byte[])candidates, UTF_8);
203
				} catch (UnsupportedEncodingException e) {
204
					JavaPlugin.log(e);
205
					return result;
206
				}
207
				distance= fDistanceAlgorithm.getDistance(word, candidate);
208
				if (distance < DISTANCE_THRESHOLD) {
209
					buffer.setLength(0);
210
					buffer.append(candidate);
211
					if (sentence)
212
						buffer.setCharAt(0, Character.toUpperCase(buffer.charAt(0)));
213
					result.add(new RankedWordProposal(buffer.toString(), -distance));
214
				}
215
				continue;
216
			}
217
218
			final ArrayList candidateList= (ArrayList)candidates;
219
			int candidateSize= Math.min(500, candidateList.size()); // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=195357
220
			for (int offset= 0; offset < candidateSize; offset++) {
221
222
				String candidate;
223
				try {
224
					candidate= new String((byte[])candidateList.get(offset), UTF_8);
225
				} catch (UnsupportedEncodingException e) {
226
					JavaPlugin.log(e);
227
					return result;
228
				}
229
				distance= fDistanceAlgorithm.getDistance(word, candidate);
230
231
				if (distance < DISTANCE_THRESHOLD) {
232
233
					buffer.setLength(0);
234
					buffer.append(candidate);
235
236
					if (sentence)
237
						buffer.setCharAt(0, Character.toUpperCase(buffer.charAt(0)));
238
239
					result.add(new RankedWordProposal(buffer.toString(), -distance));
240
				}
241
			}
242
		}
243
		return result;
244
	}
245
246
	/**
247
	 * Returns all approximations that have a phonetic hash with smallest
248
	 * possible distance to the specified word.
249
	 *
250
	 * @param word
251
	 *                   The word to find the nearest matches for
252
	 * @param sentence
253
	 *                   <code>true</code> iff the proposals start a new sentence,
254
	 *                   <code>false</code> otherwise
255
	 * @param result
256
	 *                   Set of ranked words with smallest possible distance to the
257
	 *                   specified word
258
	 */
259
	protected final void getCandidates(final String word, final boolean sentence, final Set result) {
260
261
		int distance= 0;
262
		int minimum= Integer.MAX_VALUE;
263
264
		StringBuffer buffer= new StringBuffer(BUFFER_CAPACITY);
265
266
		final Object candidates= getCandidates(fHashProvider.getHash(word));
267
		if (candidates == null)
268
			return;
269
		else if (candidates instanceof byte[]) {
270
			String candidate;
271
			try {
272
				candidate= new String((byte[])candidates, UTF_8);
273
			} catch (UnsupportedEncodingException e) {
274
				JavaPlugin.log(e);
275
				return;
276
			}
277
			distance= fDistanceAlgorithm.getDistance(word, candidate);
278
			buffer.append(candidate);
279
			if (sentence)
280
				buffer.setCharAt(0, Character.toUpperCase(buffer.charAt(0)));
281
			result.add(new RankedWordProposal(buffer.toString(), -distance));
282
			return;
283
		}
284
285
		final ArrayList candidateList= (ArrayList)candidates;
286
		final ArrayList matches= new ArrayList(candidateList.size());
287
288
		for (int index= 0; index < candidateList.size(); index++) {
289
			String candidate;
290
			try {
291
				candidate= new String((byte[])candidateList.get(index), UTF_8);
292
			} catch (UnsupportedEncodingException e) {
293
				JavaPlugin.log(e);
294
				return;
295
			}
296
			distance= fDistanceAlgorithm.getDistance(word, candidate);
297
298
			if (distance <= minimum) {
299
300
				if (distance < minimum)
301
					matches.clear();
302
303
				buffer.setLength(0);
304
				buffer.append(candidate);
305
306
				if (sentence)
307
					buffer.setCharAt(0, Character.toUpperCase(buffer.charAt(0)));
308
309
				matches.add(new RankedWordProposal(buffer.toString(), -distance));
310
				minimum= distance;
311
			}
312
		}
313
314
		result.addAll(matches);
315
	}
316
317
	/**
318
	 * Tells whether this dictionary is empty.
319
	 *
320
	 * @return <code>true</code> if this dictionary is empty
321
	 * @since 3.3
322
	 */
323
	protected boolean isEmpty() {
324
		return fHashBuckets.size() == 0;
325
	}
326
327
	/**
328
	 * Returns the used phonetic distance algorithm.
329
	 *
330
	 * @return The phonetic distance algorithm
331
	 */
332
	protected final IPhoneticDistanceAlgorithm getDistanceAlgorithm() {
333
		return fDistanceAlgorithm;
334
	}
335
336
	/**
337
	 * Returns the used phonetic hash provider.
338
	 *
339
	 * @return The phonetic hash provider
340
	 */
341
	protected final IPhoneticHashProvider getHashProvider() {
342
		return fHashProvider;
343
	}
344
345
	/*
346
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary#getProposals(java.lang.String,boolean)
347
	 */
348
	public Set getProposals(final String word, final boolean sentence) {
349
350
		try {
351
352
			if (!fLoaded) {
353
				synchronized (this) {
354
					fLoaded= load(getURL());
355
					if (fLoaded)
356
						compact();
357
				}
358
			}
359
360
		} catch (MalformedURLException exception) {
361
			// Do nothing
362
		}
363
364
		final String hash= fHashProvider.getHash(word);
365
		final char[] mutators= fHashProvider.getMutators();
366
367
		final ArrayList neighborhood= new ArrayList((word.length() + 1) * (mutators.length + 2));
368
		neighborhood.add(hash);
369
370
		final Set candidates= getCandidates(word, sentence, neighborhood);
371
		neighborhood.clear();
372
373
		char previous= 0;
374
		char next= 0;
375
376
		char[] characters= word.toCharArray();
377
		for (int index= 0; index < word.length() - 1; index++) {
378
379
			next= characters[index];
380
			previous= characters[index + 1];
381
382
			characters[index]= previous;
383
			characters[index + 1]= next;
384
385
			neighborhood.add(fHashProvider.getHash(new String(characters)));
386
387
			characters[index]= next;
388
			characters[index + 1]= previous;
389
		}
390
391
		final String sentinel= word + " "; //$NON-NLS-1$
392
393
		characters= sentinel.toCharArray();
394
		int offset= characters.length - 1;
395
396
		while (true) {
397
398
			for (int index= 0; index < mutators.length; index++) {
399
400
				characters[offset]= mutators[index];
401
				neighborhood.add(fHashProvider.getHash(new String(characters)));
402
			}
403
404
			if (offset == 0)
405
				break;
406
407
			characters[offset]= characters[offset - 1];
408
			--offset;
409
		}
410
411
		char mutated= 0;
412
		characters= word.toCharArray();
413
414
		for (int index= 0; index < word.length(); index++) {
415
416
			mutated= characters[index];
417
			for (int mutator= 0; mutator < mutators.length; mutator++) {
418
419
				characters[index]= mutators[mutator];
420
				neighborhood.add(fHashProvider.getHash(new String(characters)));
421
			}
422
			characters[index]= mutated;
423
		}
424
425
		characters= word.toCharArray();
426
		final char[] deleted= new char[characters.length - 1];
427
428
		for (int index= 0; index < deleted.length; index++)
429
			deleted[index]= characters[index];
430
431
		next= characters[characters.length - 1];
432
		offset= deleted.length;
433
434
		while (true) {
435
436
			neighborhood.add(fHashProvider.getHash(new String(characters)));
437
			if (offset == 0)
438
				break;
439
440
			previous= next;
441
			next= deleted[offset - 1];
442
443
			deleted[offset - 1]= previous;
444
			--offset;
445
		}
446
447
		neighborhood.remove(hash);
448
		final Set matches= getCandidates(word, sentence, neighborhood);
449
450
		if (matches.size() == 0 && candidates.size() == 0)
451
			getCandidates(word, sentence, candidates);
452
453
		candidates.addAll(matches);
454
455
		return candidates;
456
	}
457
458
	/**
459
	 * Returns the URL of the dictionary word list.
460
	 *
461
	 * @throws MalformedURLException
462
	 *                    if the URL could not be retrieved
463
	 * @return The URL of the dictionary word list
464
	 */
465
	protected abstract URL getURL() throws MalformedURLException;
466
467
	/**
468
	 * Hashes the word into the dictionary.
469
	 *
470
	 * @param word
471
	 *                   The word to hash in the dictionary
472
	 */
473
	protected final void hashWord(final String word) {
474
475
		final String hash= fHashProvider.getHash(word);
476
		ByteArrayWrapper hashBytes;
477
		byte[] wordBytes;
478
		try {
479
			hashBytes= new ByteArrayWrapper(hash.getBytes(UTF_8));
480
			wordBytes= word.getBytes(UTF_8);
481
		} catch (UnsupportedEncodingException e) {
482
			JavaPlugin.log(e);
483
			return;
484
		}
485
486
		Object bucket= fHashBuckets.get(hashBytes);
487
488
		if (bucket == null) {
489
			fHashBuckets.put(hashBytes, wordBytes);
490
		} else if (bucket instanceof ArrayList) {
491
			((ArrayList)bucket).add(wordBytes);
492
		} else {
493
			ArrayList list= new ArrayList(BUCKET_CAPACITY);
494
			list.add(bucket);
495
			list.add(wordBytes);
496
			fHashBuckets.put(hashBytes, list);
497
		}
498
	}
499
500
	/*
501
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary#isCorrect(java.lang.String)
502
	 */
503
	public boolean isCorrect(String word) {
504
		word= stripNonLetters(word);
505
		try {
506
507
			if (!fLoaded) {
508
				synchronized (this) {
509
					fLoaded= load(getURL());
510
					if (fLoaded)
511
						compact();
512
				}
513
			}
514
515
		} catch (MalformedURLException exception) {
516
			// Do nothing
517
		}
518
519
		final Object candidates= getCandidates(fHashProvider.getHash(word));
520
		if (candidates == null)
521
			return false;
522
		else if (candidates instanceof byte[]) {
523
			String candidate;
524
			try {
525
				candidate= new String((byte[])candidates, UTF_8);
526
			} catch (UnsupportedEncodingException e) {
527
				JavaPlugin.log(e);
528
				return false;
529
			}
530
			if (candidate.equals(word) || candidate.equals(word.toLowerCase()))
531
				return true;
532
			return false;
533
		}
534
		final ArrayList candidateList= (ArrayList)candidates;
535
		byte[] wordBytes;
536
		byte[] lowercaseWordBytes;
537
		try {
538
			wordBytes= word.getBytes(UTF_8);
539
			lowercaseWordBytes= word.toLowerCase().getBytes(UTF_8);
540
		} catch (UnsupportedEncodingException e) {
541
			JavaPlugin.log(e);
542
			return false;
543
		}
544
		for (int index= 0; index < candidateList.size(); index++) {
545
			byte[] candidate= (byte[])candidateList.get(index);
546
			if (Arrays.equals(candidate, wordBytes) || Arrays.equals(candidate, lowercaseWordBytes)) {
547
				return true;
548
			}
549
		}
550
		return false;
551
	}
552
553
	/*
554
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary#setStripNonLetters(boolean)
555
	 * @since 3.3
556
	 */
557
	public void setStripNonLetters(boolean state) {
558
		fIsStrippingNonLetters= state;
559
	}
560
561
	/**
562
	 * Strips non-letter characters from the given word.
563
	 * <p>
564
	 * This will only happen if the corresponding preference is enabled.
565
	 * </p>
566
	 *
567
	 * @param word the word to strip
568
	 * @return the stripped word
569
	 * @since 3.3
570
	 */
571
	protected String stripNonLetters(String word) {
572
		if (!fIsStrippingNonLetters)
573
			return word;
574
575
		int i= 0;
576
		int j= word.length() - 1;
577
		while (i <= j && !Character.isLetter(word.charAt(i)))
578
			i++;
579
		if (i > j)
580
			return ""; //$NON-NLS-1$
581
582
		while (j > i && !Character.isLetter(word.charAt(j)))
583
			j--;
584
585
		return word.substring(i, j+1);
586
	}
587
588
	/*
589
	 * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellDictionary#isLoaded()
590
	 */
591
	public synchronized final boolean isLoaded() {
592
		return fLoaded || fHashBuckets.size() > 0;
593
	}
594
595
	/**
596
	 * Loads a dictionary word list from disk.
597
	 *
598
	 * @param url
599
	 *                   The URL of the word list to load
600
	 * @return <code>true</code> iff the word list could be loaded, <code>false</code>
601
	 *               otherwise
602
	 */
603
	protected synchronized boolean load(final URL url) {
604
		 if (!fMustLoad)
605
			 return fLoaded;
606
607
		if (url != null) {
608
			InputStream stream= null;
609
			int line= 0;
610
			try {
611
				stream= url.openStream();
612
				if (stream != null) {
613
					String word= null;
614
615
					// Setup a reader with a decoder in order to read over malformed input if needed.
616
					CharsetDecoder decoder= Charset.forName(getEncoding()).newDecoder();
617
					decoder.onMalformedInput(CodingErrorAction.REPORT);
618
					decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
619
					final BufferedReader reader= new BufferedReader(new InputStreamReader(stream, decoder));
620
621
					boolean doRead= true;
622
					while (doRead) {
623
						try {
624
							word= reader.readLine();
625
						} catch (MalformedInputException ex) {
626
							// Tell the decoder to replace malformed input in order to read the line.
627
							decoder.onMalformedInput(CodingErrorAction.REPLACE);
628
							decoder.reset();
629
							word= reader.readLine();
630
							decoder.onMalformedInput(CodingErrorAction.REPORT);
631
632
							String message= Messages.format(JavaUIMessages.AbstractSpellingDictionary_encodingError, new String[] { word, decoder.replacement(), BasicElementLabels.getURLPart(url.toString()) });
633
							IStatus status= new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IStatus.OK, message, ex);
634
							JavaPlugin.log(status);
635
636
							doRead= word != null;
637
							continue;
638
						}
639
						doRead= word != null;
640
						if (doRead)
641
							hashWord(word);
642
					}
643
					return true;
644
				}
645
			} catch (FileNotFoundException ex) {
646
				String urlString= url.toString();
647
				String lowercaseUrlString= urlString.toLowerCase();
648
				if (urlString.equals(lowercaseUrlString))
649
					JavaPlugin.log(ex);
650
				else
651
					try {
652
						return load(new URL(lowercaseUrlString));
653
					} catch (MalformedURLException e) {
654
						JavaPlugin.log(e);
655
					}
656
			} catch (IOException exception) {
657
				if (line > 0) {
658
					String message= Messages.format(JavaUIMessages.AbstractSpellingDictionary_encodingError, new Object[] { new Integer(line), BasicElementLabels.getURLPart(url.toString()) });
659
					IStatus status= new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IStatus.OK, message, exception);
660
					JavaPlugin.log(status);
661
				} else
662
					JavaPlugin.log(exception);
663
			} finally {
664
				fMustLoad= false;
665
				try {
666
					if (stream != null)
667
						stream.close();
668
				} catch (IOException x) {
669
				}
670
			}
671
		}
672
		return false;
673
	}
674
675
	/**
676
	 * Compacts the dictionary.
677
	 *
678
	 * @since 3.3.
679
	 */
680
	private void compact() {
681
		Iterator iter= fHashBuckets.values().iterator();
682
		while (iter.hasNext()) {
683
			Object element= iter.next();
684
			if (element instanceof ArrayList)
685
				((ArrayList)element).trimToSize();
686
		}
687
	}
688
689
	/**
690
	 * Sets the phonetic distance algorithm to use.
691
	 *
692
	 * @param algorithm
693
	 *                   The phonetic distance algorithm
694
	 */
695
	protected final void setDistanceAlgorithm(final IPhoneticDistanceAlgorithm algorithm) {
696
		fDistanceAlgorithm= algorithm;
697
	}
698
699
	/**
700
	 * Sets the phonetic hash provider to use.
701
	 *
702
	 * @param provider
703
	 *                   The phonetic hash provider
704
	 */
705
	protected final void setHashProvider(final IPhoneticHashProvider provider) {
706
		fHashProvider= provider;
707
	}
708
709
	/*
710
	 * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellDictionary#unload()
711
	 */
712
	public synchronized void unload() {
713
		fLoaded= false;
714
		fMustLoad= true;
715
		fHashBuckets.clear();
716
	}
717
718
	/*
719
	 * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellDictionary#acceptsWords()
720
	 */
721
	public boolean acceptsWords() {
722
		return false;
723
	}
724
725
	/*
726
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary#addWord(java.lang.String)
727
	 */
728
	public void addWord(final String word) {
729
		// Do nothing
730
	}
731
732
	/**
733
	 * Returns the encoding of this dictionary.
734
	 *
735
	 * @return the encoding of this dictionary
736
	 * @since 3.3
737
	 */
738
	protected String getEncoding() {
739
		String encoding= JavaPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.SPELLING_USER_DICTIONARY_ENCODING);
740
		if (encoding == null || encoding.length() == 0)
741
			encoding= ResourcesPlugin.getEncoding();
742
		return encoding;
743
	}
744
745
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/engine/DefaultPhoneticDistanceAlgorithm.java (-103 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2007 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling.engine;
13
14
/**
15
 * Default phonetic distance algorithm for English words.
16
 * <p>
17
 * This algorithm implements the Levenshtein text edit distance.
18
 * </p>
19
 *
20
 * @since 3.0
21
 */
22
public final class DefaultPhoneticDistanceAlgorithm implements IPhoneticDistanceAlgorithm {
23
24
	/** The change case cost */
25
	public static final int COST_CASE= 10;
26
27
	/** The insert character cost */
28
	public static final int COST_INSERT= 95;
29
30
	/** The remove character cost */
31
	public static final int COST_REMOVE= 95;
32
33
	/** The substitute characters cost */
34
	public static final int COST_SUBSTITUTE= 100;
35
36
	/** The swap characters cost */
37
	public static final int COST_SWAP= 90;
38
39
	/*
40
	 * @see org.eclipse.spelling.done.IPhoneticDistanceAlgorithm#getDistance(java.lang.String,java.lang.String)
41
	 */
42
	public final int getDistance(final String from, final String to) {
43
44
		final char[] first= (" " + from).toCharArray(); //$NON-NLS-1$
45
		final char[] second= (" " + to).toCharArray(); //$NON-NLS-1$
46
47
		final int rows= first.length;
48
		final int columns= second.length;
49
50
		final int[][] metric= new int[rows][columns];
51
		for (int column= 1; column < columns; column++)
52
			metric[0][column]= metric[0][column - 1] + COST_REMOVE;
53
54
		for (int row= 1; row < rows; row++)
55
			metric[row][0]= metric[row - 1][0] + COST_INSERT;
56
57
		char source, target;
58
59
		int swap= Integer.MAX_VALUE;
60
		int change= Integer.MAX_VALUE;
61
62
		int minimum, diagonal, insert, remove;
63
		for (int row= 1; row < rows; row++) {
64
65
			source= first[row];
66
			for (int column= 1; column < columns; column++) {
67
68
				target= second[column];
69
				diagonal= metric[row - 1][column - 1];
70
71
				if (source == target) {
72
					metric[row][column]= diagonal;
73
					continue;
74
				}
75
76
				change= Integer.MAX_VALUE;
77
				if (Character.toLowerCase(source) == Character.toLowerCase(target))
78
					change= COST_CASE + diagonal;
79
80
				swap= Integer.MAX_VALUE;
81
				if (row != 1 && column != 1 && source == second[column - 1] && first[row - 1] == target)
82
					swap= COST_SWAP + metric[row - 2][column - 2];
83
84
				minimum= COST_SUBSTITUTE + diagonal;
85
				if (swap < minimum)
86
					minimum= swap;
87
88
				remove= metric[row][column - 1];
89
				if (COST_REMOVE + remove < minimum)
90
					minimum= COST_REMOVE + remove;
91
92
				insert= metric[row - 1][column];
93
				if (COST_INSERT + insert < minimum)
94
					minimum= COST_INSERT + insert;
95
				if (change < minimum)
96
					minimum= change;
97
98
				metric[row][column]= minimum;
99
			}
100
		}
101
		return metric[rows - 1][columns - 1];
102
	}
103
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/engine/DefaultPhoneticHashProvider.java (-683 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling.engine;
13
14
/**
15
 * Default phonetic hash provider for english languages.
16
 * <p>
17
 * This algorithm uses an adapted version double metaphone algorithm by
18
 * Lawrence Philips.
19
 * <p>
20
 *
21
 * @since 3.0
22
 */
23
public final class DefaultPhoneticHashProvider implements IPhoneticHashProvider {
24
25
	private static final String[] meta01= { "ACH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
26
	private static final String[] meta02= { "BACHER", "MACHER", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
27
	private static final String[] meta03= { "CAESAR", "" }; //$NON-NLS-1$ //$NON-NLS-2$
28
	private static final String[] meta04= { "CHIA", "" }; //$NON-NLS-1$ //$NON-NLS-2$
29
	private static final String[] meta05= { "CH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
30
	private static final String[] meta06= { "CHAE", "" }; //$NON-NLS-1$ //$NON-NLS-2$
31
	private static final String[] meta07= { "HARAC", "HARIS", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
32
	private static final String[] meta08= { "HOR", "HYM", "HIA", "HEM", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
33
	private static final String[] meta09= { "CHORE", "" }; //$NON-NLS-1$ //$NON-NLS-2$
34
	private static final String[] meta10= { "VAN ", "VON ", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
35
	private static final String[] meta11= { "SCH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
36
	private static final String[] meta12= { "ORCHES", "ARCHIT", "ORCHID", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
37
	private static final String[] meta13= { "T", "S", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
38
	private static final String[] meta14= { "A", "O", "U", "E", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
39
	private static final String[] meta15= { "L", "R", "N", "M", "B", "H", "F", "V", "W", " ", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$
40
	private static final String[] meta16= { "MC", "" }; //$NON-NLS-1$ //$NON-NLS-2$
41
	private static final String[] meta17= { "CZ", "" }; //$NON-NLS-1$ //$NON-NLS-2$
42
	private static final String[] meta18= { "WICZ", "" }; //$NON-NLS-1$ //$NON-NLS-2$
43
	private static final String[] meta19= { "CIA", "" }; //$NON-NLS-1$ //$NON-NLS-2$
44
	private static final String[] meta20= { "CC", "" }; //$NON-NLS-1$ //$NON-NLS-2$
45
	private static final String[] meta21= { "I", "E", "H", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
46
	private static final String[] meta22= { "HU", "" }; //$NON-NLS-1$ //$NON-NLS-2$
47
	private static final String[] meta23= { "UCCEE", "UCCES", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
48
	private static final String[] meta24= { "CK", "CG", "CQ", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
49
	private static final String[] meta25= { "CI", "CE", "CY", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
50
	private static final String[] meta26= { "GN", "KN", "PN", "WR", "PS", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
51
	private static final String[] meta27= { " C", " Q", " G", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
52
	private static final String[] meta28= { "C", "K", "Q", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
53
	private static final String[] meta29= { "CE", "CI", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
54
	private static final String[] meta30= { "DG", "" }; //$NON-NLS-1$ //$NON-NLS-2$
55
	private static final String[] meta31= { "I", "E", "Y", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
56
	private static final String[] meta32= { "DT", "DD", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
57
	private static final String[] meta33= { "B", "H", "D", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
58
	private static final String[] meta34= { "B", "H", "D", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
59
	private static final String[] meta35= { "B", "H", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
60
	private static final String[] meta36= { "C", "G", "L", "R", "T", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
61
	private static final String[] meta37= { "EY", "" }; //$NON-NLS-1$ //$NON-NLS-2$
62
	private static final String[] meta38= { "LI", "" }; //$NON-NLS-1$ //$NON-NLS-2$
63
	private static final String[] meta39= { "ES", "EP", "EB", "EL", "EY", "IB", "IL", "IN", "IE", "EI", "ER", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$
64
	private static final String[] meta40= { "ER", "" }; //$NON-NLS-1$ //$NON-NLS-2$
65
	private static final String[] meta41= { "DANGER", "RANGER", "MANGER", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
66
	private static final String[] meta42= { "E", "I", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
67
	private static final String[] meta43= { "RGY", "OGY", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
68
	private static final String[] meta44= { "E", "I", "Y", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
69
	private static final String[] meta45= { "AGGI", "OGGI", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
70
	private static final String[] meta46= { "VAN ", "VON ", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
71
	private static final String[] meta47= { "SCH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
72
	private static final String[] meta48= { "ET", "" }; //$NON-NLS-1$ //$NON-NLS-2$
73
	private static final String[] meta49= { "C", "X", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
74
	private static final String[] meta50= { "JOSE", "" }; //$NON-NLS-1$ //$NON-NLS-2$
75
	private static final String[] meta51= { "SAN ", "" }; //$NON-NLS-1$ //$NON-NLS-2$
76
	private static final String[] meta52= { "SAN ", "" }; //$NON-NLS-1$ //$NON-NLS-2$
77
	private static final String[] meta53= { "JOSE", "" }; //$NON-NLS-1$ //$NON-NLS-2$
78
	private static final String[] meta54= { "L", "T", "K", "S", "N", "M", "B", "Z", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$
79
	private static final String[] meta55= { "S", "K", "L", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
80
	private static final String[] meta56= { "ILLO", "ILLA", "ALLE", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
81
	private static final String[] meta57= { "AS", "OS", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
82
	private static final String[] meta58= { "A", "O", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
83
	private static final String[] meta59= { "ALLE", "" }; //$NON-NLS-1$ //$NON-NLS-2$
84
	private static final String[] meta60= { "UMB", "" }; //$NON-NLS-1$ //$NON-NLS-2$
85
	private static final String[] meta61= { "ER", "" }; //$NON-NLS-1$ //$NON-NLS-2$
86
	private static final String[] meta62= { "P", "B", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
87
	private static final String[] meta63= { "IE", "" }; //$NON-NLS-1$ //$NON-NLS-2$
88
	private static final String[] meta64= { "ME", "MA", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
89
	private static final String[] meta65= { "ISL", "YSL", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
90
	private static final String[] meta66= { "SUGAR", "" }; //$NON-NLS-1$ //$NON-NLS-2$
91
	private static final String[] meta67= { "SH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
92
	private static final String[] meta68= { "HEIM", "HOEK", "HOLM", "HOLZ", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
93
	private static final String[] meta69= { "SIO", "SIA", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
94
	private static final String[] meta70= { "SIAN", "" }; //$NON-NLS-1$ //$NON-NLS-2$
95
	private static final String[] meta71= { "M", "N", "L", "W", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
96
	private static final String[] meta72= { "Z", "" }; //$NON-NLS-1$ //$NON-NLS-2$
97
	private static final String[] meta73= { "Z", "" }; //$NON-NLS-1$ //$NON-NLS-2$
98
	private static final String[] meta74= { "SC", "" }; //$NON-NLS-1$ //$NON-NLS-2$
99
	private static final String[] meta75= { "OO", "ER", "EN", "UY", "ED", "EM", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
100
	private static final String[] meta76= { "ER", "EN", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
101
	private static final String[] meta77= { "I", "E", "Y", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
102
	private static final String[] meta78= { "AI", "OI", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
103
	private static final String[] meta79= { "S", "Z", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
104
	private static final String[] meta80= { "TION", "" }; //$NON-NLS-1$ //$NON-NLS-2$
105
	private static final String[] meta81= { "TIA", "TCH", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
106
	private static final String[] meta82= { "TH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
107
	private static final String[] meta83= { "TTH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
108
	private static final String[] meta84= { "OM", "AM", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
109
	private static final String[] meta85= { "VAN ", "VON ", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
110
	private static final String[] meta86= { "SCH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
111
	private static final String[] meta87= { "T", "D", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
112
	private static final String[] meta88= { "WR", "" }; //$NON-NLS-1$ //$NON-NLS-2$
113
	private static final String[] meta89= { "WH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
114
	private static final String[] meta90= { "EWSKI", "EWSKY", "OWSKI", "OWSKY", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
115
	private static final String[] meta91= { "SCH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
116
	private static final String[] meta92= { "WICZ", "WITZ", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
117
	private static final String[] meta93= { "IAU", "EAU", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
118
	private static final String[] meta94= { "AU", "OU", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
119
	private static final String[] meta95= { "W", "K", "CZ", "WITZ" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
120
121
	/** The mutator characters */
122
	private static final char[] MUTATOR_CHARACTERS= { 'A', 'B', 'X', 'S', 'K', 'J', 'T', 'F', 'H', 'L', 'M', 'N', 'P', 'R', '0' };
123
124
	/** The vowel characters */
125
	private static final char[] VOWEL_CHARACTERS= new char[] { 'A', 'E', 'I', 'O', 'U', 'Y' };
126
127
	/**
128
	 * Test whether the specified string contains one of the candidates in the
129
	 * list.
130
	 *
131
	 * @param candidates
132
	 *                   Array of candidates to check
133
	 * @param token
134
	 *                   The token to check for occurrences of the candidates
135
	 * @param offset
136
	 *                   The offset where to begin checking in the string
137
	 * @param length
138
	 *                   The length of the range in the string to check
139
	 * @return <code>true</code> iff the string contains one of the
140
	 *               candidates, <code>false</code> otherwise.
141
	 */
142
	protected static final boolean hasOneOf(final String[] candidates, final char[] token, final int offset, final int length) {
143
144
		if (offset < 0 || offset >= token.length || candidates.length == 0)
145
			return false;
146
147
		final String checkable= new String(token, offset, length);
148
		for (int index= 0; index < candidates.length; index++) {
149
150
			if (candidates[index].equals(checkable))
151
				return true;
152
		}
153
		return false;
154
	}
155
156
	/**
157
	 * Test whether the specified token contains one of the candidates in the
158
	 * list.
159
	 *
160
	 * @param candidates
161
	 *                   Array of candidates to check
162
	 * @param token
163
	 *                   The token to check for occurrences of the candidates
164
	 * @return <code>true</code> iff the string contains one of the
165
	 *               candidates, <code>false</code> otherwise.
166
	 */
167
	protected static final boolean hasOneOf(final String[] candidates, final String token) {
168
169
		for (int index= 0; index < candidates.length; index++) {
170
171
			if (token.indexOf(candidates[index]) >= 0)
172
				return true;
173
		}
174
		return false;
175
	}
176
177
	/**
178
	 * Tests whether the specified token contains a vowel at the specified
179
	 * offset.
180
	 *
181
	 * @param token
182
	 *                   The token to check for a vowel
183
	 * @param offset
184
	 *                   The offset where to begin checking in the token
185
	 * @param length
186
	 *                   The length of the range in the token to check
187
	 * @return <code>true</code> iff the token contains a vowel, <code>false</code>
188
	 *               otherwise.
189
	 */
190
	protected static final boolean hasVowel(final char[] token, final int offset, final int length) {
191
192
		if (offset >= 0 && offset < length) {
193
194
			final char character= token[offset];
195
			for (int index= 0; index < VOWEL_CHARACTERS.length; index++) {
196
197
				if (VOWEL_CHARACTERS[index] == character)
198
					return true;
199
			}
200
		}
201
		return false;
202
	}
203
204
	/*
205
	 * @see org.eclipse.spelling.done.IPhoneticHasher#getHash(java.lang.String)
206
	 */
207
	public final String getHash(final String word) {
208
209
		final String input= word.toUpperCase() + "     "; //$NON-NLS-1$
210
		final char[] hashable= input.toCharArray();
211
212
		final boolean has95= hasOneOf(meta95, input);
213
		final StringBuffer buffer= new StringBuffer(hashable.length);
214
215
		int offset= 0;
216
		if (hasOneOf(meta26, hashable, 0, 2))
217
			offset += 1;
218
219
		if (hashable[0] == 'X') {
220
			buffer.append('S');
221
			offset += 1;
222
		}
223
224
		while (offset < hashable.length) {
225
226
			switch (hashable[offset]) {
227
				case 'A' :
228
				case 'E' :
229
				case 'I' :
230
				case 'O' :
231
				case 'U' :
232
				case 'Y' :
233
					if (offset == 0)
234
						buffer.append('A');
235
					offset += 1;
236
					break;
237
				case 'B' :
238
					buffer.append('P');
239
					if (hashable[offset + 1] == 'B')
240
						offset += 2;
241
					else
242
						offset += 1;
243
					break;
244
				case 'C' :
245
					if ((offset > 1) && !hasVowel(hashable, offset - 2, hashable.length) && hasOneOf(meta01, hashable, (offset - 1), 3) && (hashable[offset + 2] != 'I') && (hashable[offset + 2] != 'E') || hasOneOf(meta02, hashable, (offset - 2), 6)) {
246
						buffer.append('K');
247
						offset += 2;
248
						break;
249
					}
250
					if ((offset == 0) && hasOneOf(meta03, hashable, offset, 6)) {
251
						buffer.append('S');
252
						offset += 2;
253
						break;
254
					}
255
					if (hasOneOf(meta04, hashable, offset, 4)) {
256
						buffer.append('K');
257
						offset += 2;
258
						break;
259
					}
260
					if (hasOneOf(meta05, hashable, offset, 2)) {
261
						if ((offset > 0) && hasOneOf(meta06, hashable, offset, 4)) {
262
							buffer.append('K');
263
							offset += 2;
264
							break;
265
						}
266
						if ((offset == 0) && hasOneOf(meta07, hashable, (offset + 1), 5) || hasOneOf(meta08, hashable, offset + 1, 3) && !hasOneOf(meta09, hashable, 0, 5)) {
267
							buffer.append('K');
268
							offset += 2;
269
							break;
270
						}
271
						if (hasOneOf(meta10, hashable, 0, 4) || hasOneOf(meta11, hashable, 0, 3) || hasOneOf(meta12, hashable, offset - 2, 6) || hasOneOf(meta13, hashable, offset + 2, 1) || (hasOneOf(meta14, hashable, offset - 1, 1) || (offset == 0)) && hasOneOf(meta15, hashable, offset + 2, 1)) {
272
							buffer.append('K');
273
						} else {
274
							if (offset > 0) {
275
								if (hasOneOf(meta16, hashable, 0, 2))
276
									buffer.append('K');
277
								else
278
									buffer.append('X');
279
							} else {
280
								buffer.append('X');
281
							}
282
						}
283
						offset += 2;
284
						break;
285
					}
286
					if (hasOneOf(meta17, hashable, offset, 2) && !hasOneOf(meta18, hashable, offset, 4)) {
287
						buffer.append('S');
288
						offset += 2;
289
						break;
290
					}
291
					if (hasOneOf(meta19, hashable, offset, 2)) {
292
						buffer.append('X');
293
						offset += 2;
294
						break;
295
					}
296
					if (hasOneOf(meta20, hashable, offset, 2) && !((offset == 1) && hashable[0] == 'M')) {
297
						if (hasOneOf(meta21, hashable, offset + 2, 1) && !hasOneOf(meta22, hashable, offset + 2, 2)) {
298
							if (((offset == 1) && (hashable[offset - 1] == 'A')) || hasOneOf(meta23, hashable, (offset - 1), 5))
299
								buffer.append("KS"); //$NON-NLS-1$
300
							else
301
								buffer.append('X');
302
							offset += 3;
303
							break;
304
						} else {
305
							buffer.append('K');
306
							offset += 2;
307
							break;
308
						}
309
					}
310
					if (hasOneOf(meta24, hashable, offset, 2)) {
311
						buffer.append('K');
312
						offset += 2;
313
						break;
314
					} else if (hasOneOf(meta25, hashable, offset, 2)) {
315
						buffer.append('S');
316
						offset += 2;
317
						break;
318
					}
319
					buffer.append('K');
320
					if (hasOneOf(meta27, hashable, offset + 1, 2))
321
						offset += 3;
322
					else if (hasOneOf(meta28, hashable, offset + 1, 1) && !hasOneOf(meta29, hashable, offset + 1, 2))
323
						offset += 2;
324
					else
325
						offset += 1;
326
					break;
327
				case '\u00C7' :
328
					buffer.append('S');
329
					offset += 1;
330
					break;
331
				case 'D' :
332
					if (hasOneOf(meta30, hashable, offset, 2)) {
333
						if (hasOneOf(meta31, hashable, offset + 2, 1)) {
334
							buffer.append('J');
335
							offset += 3;
336
							break;
337
						} else {
338
							buffer.append("TK"); //$NON-NLS-1$
339
							offset += 2;
340
							break;
341
						}
342
					}
343
					buffer.append('T');
344
					if (hasOneOf(meta32, hashable, offset, 2)) {
345
						offset += 2;
346
					} else {
347
						offset += 1;
348
					}
349
					break;
350
				case 'F' :
351
					if (hashable[offset + 1] == 'F')
352
						offset += 2;
353
					else
354
						offset += 1;
355
					buffer.append('F');
356
					break;
357
				case 'G' :
358
					if (hashable[offset + 1] == 'H') {
359
						if ((offset > 0) && !hasVowel(hashable, offset - 1, hashable.length)) {
360
							buffer.append('K');
361
							offset += 2;
362
							break;
363
						}
364
						if (offset < 3) {
365
							if (offset == 0) {
366
								if (hashable[offset + 2] == 'I')
367
									buffer.append('J');
368
								else
369
									buffer.append('K');
370
								offset += 2;
371
								break;
372
							}
373
						}
374
						if ((offset > 1) && hasOneOf(meta33, hashable, offset - 2, 1) || ((offset > 2) && hasOneOf(meta34, hashable, offset - 3, 1)) || ((offset > 3) && hasOneOf(meta35, hashable, offset - 4, 1))) {
375
							offset += 2;
376
							break;
377
						} else {
378
							if ((offset > 2) && (hashable[offset - 1] == 'U') && hasOneOf(meta36, hashable, offset - 3, 1)) {
379
								buffer.append('F');
380
							} else {
381
								if ((offset > 0) && (hashable[offset - 1] != 'I'))
382
									buffer.append('K');
383
							}
384
							offset += 2;
385
							break;
386
						}
387
					}
388
					if (hashable[offset + 1] == 'N') {
389
						if ((offset == 1) && hasVowel(hashable, 0, hashable.length) && !has95) {
390
							buffer.append("KN"); //$NON-NLS-1$
391
						} else {
392
							if (!hasOneOf(meta37, hashable, offset + 2, 2) && (hashable[offset + 1] != 'Y') && !has95) {
393
								buffer.append("N"); //$NON-NLS-1$
394
							} else {
395
								buffer.append("KN"); //$NON-NLS-1$
396
							}
397
						}
398
						offset += 2;
399
						break;
400
					}
401
					if (hasOneOf(meta38, hashable, offset + 1, 2) && !has95) {
402
						buffer.append("KL"); //$NON-NLS-1$
403
						offset += 2;
404
						break;
405
					}
406
					if ((offset == 0) && ((hashable[offset + 1] == 'Y') || hasOneOf(meta39, hashable, offset + 1, 2))) {
407
						buffer.append('K');
408
						offset += 2;
409
						break;
410
					}
411
					if ((hasOneOf(meta40, hashable, offset + 1, 2) || (hashable[offset + 1] == 'Y')) && !hasOneOf(meta41, hashable, 0, 6) && !hasOneOf(meta42, hashable, offset - 1, 1) && !hasOneOf(meta43, hashable, offset - 1, 3)) {
412
						buffer.append('K');
413
						offset += 2;
414
						break;
415
					}
416
					if (hasOneOf(meta44, hashable, offset + 1, 1) || hasOneOf(meta45, hashable, offset - 1, 4)) {
417
						if (hasOneOf(meta46, hashable, 0, 4) || hasOneOf(meta47, hashable, 0, 3) || hasOneOf(meta48, hashable, offset + 1, 2)) {
418
							buffer.append('K');
419
						} else {
420
							buffer.append('J');
421
						}
422
						offset += 2;
423
						break;
424
					}
425
					if (hashable[offset + 1] == 'G')
426
						offset += 2;
427
					else
428
						offset += 1;
429
					buffer.append('K');
430
					break;
431
				case 'H' :
432
					if (((offset == 0) || hasVowel(hashable, offset - 1, hashable.length)) && hasVowel(hashable, offset + 1, hashable.length)) {
433
						buffer.append('H');
434
						offset += 2;
435
					} else {
436
						offset += 1;
437
					}
438
					break;
439
				case 'J' :
440
					if (hasOneOf(meta50, hashable, offset, 4) || hasOneOf(meta51, hashable, 0, 4)) {
441
						if ((offset == 0) && (hashable[offset + 4] == ' ') || hasOneOf(meta52, hashable, 0, 4)) {
442
							buffer.append('H');
443
						} else {
444
							buffer.append('J');
445
						}
446
						offset += 1;
447
						break;
448
					}
449
					if ((offset == 0) && !hasOneOf(meta53, hashable, offset, 4)) {
450
						buffer.append('J');
451
					} else {
452
						if (hasVowel(hashable, offset - 1, hashable.length) && !has95 && ((hashable[offset + 1] == 'A') || hashable[offset + 1] == 'O')) {
453
							buffer.append('J');
454
						} else {
455
							if (offset == (hashable.length - 1)) {
456
								buffer.append('J');
457
							} else {
458
								if (!hasOneOf(meta54, hashable, offset + 1, 1) && !hasOneOf(meta55, hashable, offset - 1, 1)) {
459
									buffer.append('J');
460
								}
461
							}
462
						}
463
					}
464
					if (hashable[offset + 1] == 'J')
465
						offset += 2;
466
					else
467
						offset += 1;
468
					break;
469
				case 'K' :
470
					if (hashable[offset + 1] == 'K')
471
						offset += 2;
472
					else
473
						offset += 1;
474
					buffer.append('K');
475
					break;
476
				case 'L' :
477
					if (hashable[offset + 1] == 'L') {
478
						if (((offset == (hashable.length - 3)) && hasOneOf(meta56, hashable, offset - 1, 4)) || ((hasOneOf(meta57, hashable, (hashable.length - 1) - 1, 2) || hasOneOf(meta58, hashable, hashable.length - 1, 1)) && hasOneOf(meta59, hashable, offset - 1, 4))) {
479
							buffer.append('L');
480
							offset += 2;
481
							break;
482
						}
483
						offset += 2;
484
					} else
485
						offset += 1;
486
					buffer.append('L');
487
					break;
488
				case 'M' :
489
					if ((hasOneOf(meta60, hashable, offset - 1, 3) && (((offset + 1) == (hashable.length - 1)) || hasOneOf(meta61, hashable, offset + 2, 2))) || (hashable[offset + 1] == 'M'))
490
						offset += 2;
491
					else
492
						offset += 1;
493
					buffer.append('M');
494
					break;
495
				case 'N' :
496
					if (hashable[offset + 1] == 'N')
497
						offset += 2;
498
					else
499
						offset += 1;
500
					buffer.append('N');
501
					break;
502
				case '\u00D1' :
503
					offset += 1;
504
					buffer.append('N');
505
					break;
506
				case 'P' :
507
					if (hashable[offset + 1] == 'N') {
508
						buffer.append('F');
509
						offset += 2;
510
						break;
511
					}
512
					if (hasOneOf(meta62, hashable, offset + 1, 1))
513
						offset += 2;
514
					else
515
						offset += 1;
516
					buffer.append('P');
517
					break;
518
				case 'Q' :
519
					if (hashable[offset + 1] == 'Q')
520
						offset += 2;
521
					else
522
						offset += 1;
523
					buffer.append('K');
524
					break;
525
				case 'R' :
526
					if (!((offset == (hashable.length - 1)) && !has95 && hasOneOf(meta63, hashable, offset - 2, 2) && !hasOneOf(meta64, hashable, offset - 4, 2)))
527
						buffer.append('R');
528
					if (hashable[offset + 1] == 'R')
529
						offset += 2;
530
					else
531
						offset += 1;
532
					break;
533
				case 'S' :
534
					if (hasOneOf(meta65, hashable, offset - 1, 3)) {
535
						offset += 1;
536
						break;
537
					}
538
					if ((offset == 0) && hasOneOf(meta66, hashable, offset, 5)) {
539
						buffer.append('X');
540
						offset += 1;
541
						break;
542
					}
543
					if (hasOneOf(meta67, hashable, offset, 2)) {
544
						if (hasOneOf(meta68, hashable, offset + 1, 4))
545
							buffer.append('S');
546
						else
547
							buffer.append('X');
548
						offset += 2;
549
						break;
550
					}
551
					if (hasOneOf(meta69, hashable, offset, 3) || hasOneOf(meta70, hashable, offset, 4)) {
552
						buffer.append('S');
553
						offset += 3;
554
						break;
555
					}
556
					if (((offset == 0) && hasOneOf(meta71, hashable, offset + 1, 1)) || hasOneOf(meta72, hashable, offset + 1, 1)) {
557
						buffer.append('S');
558
						if (hasOneOf(meta73, hashable, offset + 1, 1))
559
							offset += 2;
560
						else
561
							offset += 1;
562
						break;
563
					}
564
					if (hasOneOf(meta74, hashable, offset, 2)) {
565
						if (hashable[offset + 2] == 'H')
566
							if (hasOneOf(meta75, hashable, offset + 3, 2)) {
567
								if (hasOneOf(meta76, hashable, offset + 3, 2)) {
568
									buffer.append("X"); //$NON-NLS-1$
569
								} else {
570
									buffer.append("SK"); //$NON-NLS-1$
571
								}
572
								offset += 3;
573
								break;
574
							} else {
575
								buffer.append('X');
576
								offset += 3;
577
								break;
578
							}
579
						if (hasOneOf(meta77, hashable, offset + 2, 1)) {
580
							buffer.append('S');
581
							offset += 3;
582
							break;
583
						}
584
						buffer.append("SK"); //$NON-NLS-1$
585
						offset += 3;
586
						break;
587
					}
588
					if (!((offset == (hashable.length - 1)) && hasOneOf(meta78, hashable, offset - 2, 2)))
589
						buffer.append('S');
590
					if (hasOneOf(meta79, hashable, offset + 1, 1))
591
						offset += 2;
592
					else
593
						offset += 1;
594
					break;
595
				case 'T' :
596
					if (hasOneOf(meta80, hashable, offset, 4)) {
597
						buffer.append('X');
598
						offset += 3;
599
						break;
600
					}
601
					if (hasOneOf(meta81, hashable, offset, 3)) {
602
						buffer.append('X');
603
						offset += 3;
604
						break;
605
					}
606
					if (hasOneOf(meta82, hashable, offset, 2) || hasOneOf(meta83, hashable, offset, 3)) {
607
						if (hasOneOf(meta84, hashable, (offset + 2), 2) || hasOneOf(meta85, hashable, 0, 4) || hasOneOf(meta86, hashable, 0, 3)) {
608
							buffer.append('T');
609
						} else {
610
							buffer.append('0');
611
						}
612
						offset += 2;
613
						break;
614
					}
615
					if (hasOneOf(meta87, hashable, offset + 1, 1)) {
616
						offset += 2;
617
					} else
618
						offset += 1;
619
					buffer.append('T');
620
					break;
621
				case 'V' :
622
					if (hashable[offset + 1] == 'V')
623
						offset += 2;
624
					else
625
						offset += 1;
626
					buffer.append('F');
627
					break;
628
				case 'W' :
629
					if (hasOneOf(meta88, hashable, offset, 2)) {
630
						buffer.append('R');
631
						offset += 2;
632
						break;
633
					}
634
					if ((offset == 0) && (hasVowel(hashable, offset + 1, hashable.length) || hasOneOf(meta89, hashable, offset, 2))) {
635
						buffer.append('A');
636
					}
637
					if (((offset == (hashable.length - 1)) && hasVowel(hashable, offset - 1, hashable.length)) || hasOneOf(meta90, hashable, offset - 1, 5) || hasOneOf(meta91, hashable, 0, 3)) {
638
						buffer.append('F');
639
						offset += 1;
640
						break;
641
					}
642
					if (hasOneOf(meta92, hashable, offset, 4)) {
643
						buffer.append("TS"); //$NON-NLS-1$
644
						offset += 4;
645
						break;
646
					}
647
					offset += 1;
648
					break;
649
				case 'X' :
650
					if (!((offset == (hashable.length - 1)) && (hasOneOf(meta93, hashable, offset - 3, 3) || hasOneOf(meta94, hashable, offset - 2, 2))))
651
						buffer.append("KS"); //$NON-NLS-1$
652
					if (hasOneOf(meta49, hashable, offset + 1, 1))
653
						offset += 2;
654
					else
655
						offset += 1;
656
					break;
657
				case 'Z' :
658
					if (hashable[offset + 1] == 'H') {
659
						buffer.append('J');
660
						offset += 2;
661
						break;
662
					} else {
663
						buffer.append('S');
664
					}
665
					if (hashable[offset + 1] == 'Z')
666
						offset += 2;
667
					else
668
						offset += 1;
669
					break;
670
				default :
671
					offset += 1;
672
			}
673
		}
674
		return buffer.toString();
675
	}
676
677
	/*
678
	 * @see org.eclipse.spelling.done.IPhoneticHasher#getMutators()
679
	 */
680
	public final char[] getMutators() {
681
		return MUTATOR_CHARACTERS;
682
	}
683
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/engine/DefaultSpellChecker.java (-344 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.ui.text.spelling.engine;
12
13
import java.util.Collections;
14
import java.util.HashSet;
15
import java.util.Iterator;
16
import java.util.Locale;
17
import java.util.Set;
18
19
import org.eclipse.core.runtime.Assert;
20
21
import org.eclipse.jface.preference.IPreferenceStore;
22
23
import org.eclipse.jdt.ui.PreferenceConstants;
24
25
26
/**
27
 * Default spell checker for standard text.
28
 *
29
 * @since 3.0
30
 */
31
public class DefaultSpellChecker implements ISpellChecker {
32
33
	/** Array of URL prefixes */
34
	public static final String[] URL_PREFIXES= new String[] { "http://", "https://", "www.", "ftp://", "ftps://", "news://", "mailto://" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
35
36
	/**
37
	 * Does this word contain digits?
38
	 *
39
	 * @param word the word to check
40
	 * @return <code>true</code> iff this word contains digits, <code>false></code> otherwise
41
	 */
42
	protected static boolean isDigits(final String word) {
43
44
		for (int index= 0; index < word.length(); index++) {
45
46
			if (Character.isDigit(word.charAt(index)))
47
				return true;
48
		}
49
		return false;
50
	}
51
52
	/**
53
	 * Does this word contain mixed-case letters?
54
	 *
55
	 * @param word
56
	 *                   The word to check
57
	 * @param sentence
58
	 *                   <code>true</code> iff the specified word starts a new
59
	 *                   sentence, <code>false</code> otherwise
60
	 * @return <code>true</code> iff the contains mixed-case letters, <code>false</code>
61
	 *               otherwise
62
	 */
63
	protected static boolean isMixedCase(final String word, final boolean sentence) {
64
65
		final int length= word.length();
66
		boolean upper= Character.isUpperCase(word.charAt(0));
67
68
		if (sentence && upper && (length > 1))
69
			upper= Character.isUpperCase(word.charAt(1));
70
71
		if (upper) {
72
73
			for (int index= length - 1; index > 0; index--) {
74
				if (Character.isLowerCase(word.charAt(index)))
75
					return true;
76
			}
77
		} else {
78
79
			for (int index= length - 1; index > 0; index--) {
80
				if (Character.isUpperCase(word.charAt(index)))
81
					return true;
82
			}
83
		}
84
		return false;
85
	}
86
87
	/**
88
	 * Does this word contain upper-case letters only?
89
	 *
90
	 * @param word
91
	 *                   The word to check
92
	 * @return <code>true</code> iff this word only contains upper-case
93
	 *               letters, <code>false</code> otherwise
94
	 */
95
	protected static boolean isUpperCase(final String word) {
96
97
		for (int index= word.length() - 1; index >= 0; index--) {
98
99
			if (Character.isLowerCase(word.charAt(index)))
100
				return false;
101
		}
102
		return true;
103
	}
104
105
	/**
106
	 * Does this word look like an URL?
107
	 *
108
	 * @param word
109
	 *                   The word to check
110
	 * @return <code>true</code> iff this word looks like an URL, <code>false</code>
111
	 *               otherwise
112
	 */
113
	protected static boolean isUrl(final String word) {
114
115
		for (int index= 0; index < URL_PREFIXES.length; index++) {
116
117
			if (word.startsWith(URL_PREFIXES[index]))
118
				return true;
119
		}
120
		return false;
121
	}
122
123
	/**
124
	 * The dictionaries to use for spell checking. Synchronized to avoid
125
	 * concurrent modifications.
126
	 */
127
	private final Set fDictionaries= Collections.synchronizedSet(new HashSet());
128
129
	/**
130
	 * The words to be ignored. Synchronized to avoid concurrent modifications.
131
	 */
132
	private final Set fIgnored= Collections.synchronizedSet(new HashSet());
133
134
	/**
135
	 * The preference store. Assumes the <code>IPreferenceStore</code>
136
	 * implementation is thread safe.
137
	 */
138
	private final IPreferenceStore fPreferences;
139
140
	/**
141
	 * The locale of this checker.
142
	 * @since 3.3
143
	 */
144
	private Locale fLocale;
145
146
	/**
147
	 * Creates a new default spell checker.
148
	 *
149
	 * @param store the preference store for this spell checker
150
	 * @param locale the locale
151
	 */
152
	public DefaultSpellChecker(IPreferenceStore store, Locale locale) {
153
		Assert.isLegal(store != null);
154
		Assert.isLegal(locale != null);
155
156
		fPreferences= store;
157
		fLocale= locale;
158
	}
159
160
	/*
161
	 * @see org.eclipse.spelling.done.ISpellChecker#addDictionary(org.eclipse.spelling.done.ISpellDictionary)
162
	 */
163
	public final void addDictionary(final ISpellDictionary dictionary) {
164
		// synchronizing is necessary as this is a write access
165
		fDictionaries.add(dictionary);
166
	}
167
168
	/*
169
	 * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellChecker#acceptsWords()
170
	 */
171
	public boolean acceptsWords() {
172
		// synchronizing might not be needed here since acceptWords is
173
		// a read-only access and only called in the same thread as
174
		// the modifying methods add/checkWord (?)
175
		Set copy;
176
		synchronized (fDictionaries) {
177
			copy= new HashSet(fDictionaries);
178
		}
179
180
		ISpellDictionary dictionary= null;
181
		for (final Iterator iterator= copy.iterator(); iterator.hasNext();) {
182
183
			dictionary= (ISpellDictionary)iterator.next();
184
			if (dictionary.acceptsWords())
185
				return true;
186
		}
187
		return false;
188
	}
189
190
	/*
191
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker#addWord(java.lang.String)
192
	 */
193
	public void addWord(final String word) {
194
		// synchronizing is necessary as this is a write access
195
		Set copy;
196
		synchronized (fDictionaries) {
197
			copy= new HashSet(fDictionaries);
198
		}
199
200
		final String addable= word.toLowerCase();
201
		for (final Iterator iterator= copy.iterator(); iterator.hasNext();) {
202
			ISpellDictionary dictionary= (ISpellDictionary)iterator.next();
203
			if (dictionary.acceptsWords())
204
				dictionary.addWord(addable);
205
		}
206
207
	}
208
209
	/*
210
	 * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellChecker#checkWord(java.lang.String)
211
	 */
212
	public final void checkWord(final String word) {
213
		// synchronizing is necessary as this is a write access
214
		fIgnored.remove(word.toLowerCase());
215
	}
216
217
	/*
218
	 * @see org.eclipse.spelling.done.ISpellChecker#execute(org.eclipse.spelling.ISpellCheckTokenizer)
219
	 */
220
	public void execute(final ISpellEventListener listener, final ISpellCheckIterator iterator) {
221
222
		final boolean ignoreDigits= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_DIGITS);
223
		final boolean ignoreMixed= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_MIXED);
224
		final boolean ignoreSentence= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_SENTENCE);
225
		final boolean ignoreUpper= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_UPPER);
226
		final boolean ignoreURLS= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_URLS);
227
		final boolean ignoreNonLetters= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_NON_LETTERS);
228
		final boolean ignoreSingleLetters= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_SINGLE_LETTERS);
229
		final int problemsThreshold= PreferenceConstants.getPreferenceStore().getInt(PreferenceConstants.SPELLING_PROBLEMS_THRESHOLD);
230
231
		iterator.setIgnoreSingleLetters(ignoreSingleLetters);
232
233
		Iterator iter= fDictionaries.iterator();
234
		while (iter.hasNext())
235
			((ISpellDictionary)iter.next()).setStripNonLetters(ignoreNonLetters);
236
237
		String word= null;
238
		boolean starts= false;
239
		int problemCount= 0;
240
241
		while (problemCount <= problemsThreshold && iterator.hasNext()) {
242
243
			word= (String)iterator.next();
244
			if (word != null) {
245
246
				// synchronizing is necessary as this is called inside the reconciler
247
				if (!fIgnored.contains(word)) {
248
249
					starts= iterator.startsSentence();
250
					if (!isCorrect(word)) {
251
252
					    boolean isMixed=  isMixedCase(word, true);
253
					    boolean isUpper= isUpperCase(word);
254
					    boolean isDigits= isDigits(word);
255
					    boolean isURL= isUrl(word);
256
257
					    if ( !ignoreMixed && isMixed || !ignoreUpper && isUpper || !ignoreDigits && isDigits || !ignoreURLS && isURL || !(isMixed || isUpper || isDigits || isURL)) {
258
					        listener.handle(new SpellEvent(this, word, iterator.getBegin(), iterator.getEnd(), starts, false));
259
					        problemCount++;
260
					    }
261
262
					} else {
263
264
						if (!ignoreSentence && starts && Character.isLowerCase(word.charAt(0))) {
265
							listener.handle(new SpellEvent(this, word, iterator.getBegin(), iterator.getEnd(), true, true));
266
							problemCount++;
267
						}
268
					}
269
				}
270
			}
271
		}
272
	}
273
274
	/*
275
	 * @see org.eclipse.spelling.done.ISpellChecker#getProposals(java.lang.String,boolean)
276
	 */
277
	public Set getProposals(final String word, final boolean sentence) {
278
279
		// synchronizing might not be needed here since getProposals is
280
		// a read-only access and only called in the same thread as
281
		// the modifing methods add/removeDictionary (?)
282
		Set copy;
283
		synchronized (fDictionaries) {
284
			copy= new HashSet(fDictionaries);
285
		}
286
287
		ISpellDictionary dictionary= null;
288
		final HashSet proposals= new HashSet();
289
290
		for (final Iterator iterator= copy.iterator(); iterator.hasNext();) {
291
292
			dictionary= (ISpellDictionary)iterator.next();
293
			proposals.addAll(dictionary.getProposals(word, sentence));
294
		}
295
		return proposals;
296
	}
297
298
	/*
299
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker#ignoreWord(java.lang.String)
300
	 */
301
	public final void ignoreWord(final String word) {
302
		// synchronizing is necessary as this is a write access
303
		fIgnored.add(word.toLowerCase());
304
	}
305
306
	/*
307
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker#isCorrect(java.lang.String)
308
	 */
309
	public final boolean isCorrect(final String word) {
310
		// synchronizing is necessary as this is called from execute
311
		Set copy;
312
		synchronized (fDictionaries) {
313
			copy= new HashSet(fDictionaries);
314
		}
315
316
		if (fIgnored.contains(word.toLowerCase()))
317
			return true;
318
319
		ISpellDictionary dictionary= null;
320
		for (final Iterator iterator= copy.iterator(); iterator.hasNext();) {
321
322
			dictionary= (ISpellDictionary)iterator.next();
323
			if (dictionary.isCorrect(word))
324
				return true;
325
		}
326
		return false;
327
	}
328
329
	/*
330
	 * @see org.eclipse.spelling.done.ISpellChecker#removeDictionary(org.eclipse.spelling.done.ISpellDictionary)
331
	 */
332
	public final void removeDictionary(final ISpellDictionary dictionary) {
333
		// synchronizing is necessary as this is a write access
334
		fDictionaries.remove(dictionary);
335
	}
336
337
	/*
338
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker#getLocale()
339
	 * @since 3.3
340
	 */
341
	public Locale getLocale() {
342
		return fLocale;
343
	}
344
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/engine/IPhoneticDistanceAlgorithm.java (-31 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling.engine;
13
14
/**
15
 * Interface of algorithms to compute the phonetic distance between two words.
16
 *
17
 * @since 3.0
18
 */
19
public interface IPhoneticDistanceAlgorithm {
20
21
	/**
22
	 * Returns the non-negative phonetic distance between two words
23
	 *
24
	 * @param from
25
	 *                  The first word
26
	 * @param to
27
	 *                  The second word
28
	 * @return The non-negative phonetic distance between the words.
29
	 */
30
	public int getDistance(String from, String to);
31
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/engine/IPhoneticHashProvider.java (-36 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling.engine;
13
14
/**
15
 * Interface of hashers to compute the phonetic hash for a word.
16
 *
17
 * @since 3.0
18
 */
19
public interface IPhoneticHashProvider {
20
21
	/**
22
	 * Returns the phonetic hash for the word.
23
	 *
24
	 * @param word
25
	 *                  The word to get the phonetic hash for
26
	 * @return The phonetic hash for the word
27
	 */
28
	public String getHash(String word);
29
30
	/**
31
	 * Returns an array of characters to compute possible mutations.
32
	 *
33
	 * @return Array of possible mutator characters
34
	 */
35
	public char[] getMutators();
36
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/engine/ISpellCheckEngine.java (-84 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling.engine;
13
14
import java.util.Locale;
15
16
import org.eclipse.jdt.ui.PreferenceConstants;
17
18
/**
19
 * Interface for a spell check engine.
20
 * <p>
21
 * This engine can be configured with multiple
22
 * dictionaries.
23
 * </p>
24
 *
25
 * @since 3.0
26
 */
27
public interface ISpellCheckEngine {
28
29
	/**
30
	 * Returns a spell checker configured with the global
31
	 * dictionaries and the locale dictionary that correspond to the current
32
	 * {@linkplain PreferenceConstants#SPELLING_LOCALE locale preference}.
33
	 * <p>
34
	 * <strong>Note:</strong> Changes to the spelling engine dictionaries
35
	 * are not propagated to this spell checker.</p>
36
	 *
37
	 * @return a configured instance of the spell checker or <code>null</code> if none
38
	 * @throws IllegalStateException if called after being shut down
39
	 */
40
	ISpellChecker getSpellChecker() throws IllegalStateException;
41
42
	/**
43
	 * Returns the locale of the current spell check engine.
44
	 *
45
	 * @return the locale of the current spell check engine
46
	 */
47
	Locale getLocale();
48
49
	/**
50
	 * Registers a global dictionary.
51
	 *
52
	 * @param dictionary the global dictionary to register
53
	 */
54
	void registerGlobalDictionary(ISpellDictionary dictionary);
55
56
	/**
57
	 * Registers a dictionary tuned for the specified locale with this engine.
58
	 *
59
	 * @param locale
60
	 *                   The locale to register the dictionary with
61
	 * @param dictionary
62
	 *                   The dictionary to register
63
	 */
64
	void registerDictionary(Locale locale, ISpellDictionary dictionary);
65
66
	/**
67
	 * Shuts down this spell check engine and its associated components.
68
	 * <p>
69
	 * Further calls to this engine result in exceptions.
70
	 * </p>
71
	 */
72
	void shutdown();
73
74
	/**
75
	 * Unregisters a dictionary previously registered either by a call to
76
	 * <code>registerDictionary(Locale,ISpellDictionary)</code> or <code>registerDictionary(ISpellDictionary)</code>.
77
	 * <p>
78
	 * If the dictionary was not registered before, nothing happens.</p>
79
	 *
80
	 * @param dictionary the dictionary to unregister
81
	 */
82
	void unregisterDictionary(ISpellDictionary dictionary);
83
84
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/engine/ISpellCheckIterator.java (-52 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling.engine;
13
14
import java.util.Iterator;
15
16
/**
17
 * Interface for iterators used for spell checking.
18
 *
19
 * @since 3.0
20
 */
21
public interface ISpellCheckIterator extends Iterator {
22
23
	/**
24
	 * Returns the begin index (inclusive) of the current word.
25
	 *
26
	 * @return The begin index of the current word
27
	 */
28
	public int getBegin();
29
30
	/**
31
	 * Returns the end index (exclusive) of the current word.
32
	 *
33
	 * @return The end index of the current word
34
	 */
35
	public int getEnd();
36
37
	/**
38
	 * Does the current word start a new sentence?
39
	 *
40
	 * @return <code>true<code> iff the current word starts a new sentence, <code>false</code> otherwise
41
	 */
42
	public boolean startsSentence();
43
44
	/**
45
	 * Tells whether to ignore single letters
46
	 * from being checked.
47
	 *
48
	 * @since 3.3
49
	 * @param state <code>true</code> if single letters should be ignored
50
	 */
51
	public void setIgnoreSingleLetters(boolean state);
52
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/engine/ISpellChecker.java (-110 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling.engine;
13
14
import java.util.Locale;
15
import java.util.Set;
16
17
/**
18
 * Interface for spell checkers.
19
 *
20
 * @since 3.0
21
 */
22
public interface ISpellChecker {
23
24
	/**
25
	 * Adds a dictionary to the list of active dictionaries.
26
	 *
27
	 * @param dictionary
28
	 *                   The dictionary to add
29
	 */
30
	void addDictionary(ISpellDictionary dictionary);
31
32
	/**
33
	 * Returns whether this spell checker accepts word additions.
34
	 *
35
	 * @return <code>true</code> if word additions are accepted, <code>false</code> otherwise
36
	 */
37
	boolean acceptsWords();
38
39
	/**
40
	 * Adds the specified word to the set of correct words.
41
	 *
42
	 * @param word
43
	 *                   The word to add to the set of correct words
44
	 */
45
	void addWord(String word);
46
47
	/**
48
	 * Checks the specified word until calling <code>ignoreWord(String)</code>.
49
	 *
50
	 * @param word
51
	 *                   The word to check
52
	 */
53
	void checkWord(String word);
54
55
	/**
56
	 * Checks the spelling with the spell check iterator. Implementations must
57
	 * be thread safe as this may be called inside a reconciler thread.
58
	 *
59
	 * @param listener the spell event listener
60
	 * @param iterator the iterator to use for spell checking
61
	 */
62
	void execute(ISpellEventListener listener, ISpellCheckIterator iterator);
63
64
	/**
65
	 * Returns the ranked proposals for a word.
66
	 *
67
	 * @param word
68
	 *                   The word to retrieve the proposals for
69
	 * @param sentence
70
	 *                   <code>true</code> iff the proposals should start a
71
	 *                   sentence, <code>false</code> otherwise
72
	 * @return Set of ranked proposals for the word
73
	 */
74
	Set getProposals(String word, boolean sentence);
75
76
	/**
77
	 * Ignores the specified word until calling <code>checkWord(String)</code>.
78
	 *
79
	 * @param word
80
	 *                   The word to ignore
81
	 */
82
	void ignoreWord(String word);
83
84
	/**
85
	 * Is the specified word correctly spelled? Implementations must be thread
86
	 * safe as this may be called from within a reconciler thread.
87
	 *
88
	 * @param word
89
	 *                   The word to check its spelling
90
	 * @return <code>true</code> iff the word is correctly spelled, <code>false</code>
91
	 *               otherwise
92
	 */
93
	boolean isCorrect(String word);
94
95
	/**
96
	 * Remove a dictionary from the list of active dictionaries.
97
	 *
98
	 * @param dictionary
99
	 *                   The dictionary to remove
100
	 */
101
	void removeDictionary(ISpellDictionary dictionary);
102
103
	/**
104
	 * Returns the current locale of the spell check engine.
105
	 *
106
	 * @return The current locale of the engine
107
	 * @since 3.3
108
	 */
109
	Locale getLocale();
110
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/engine/ISpellDictionary.java (-77 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling.engine;
13
14
import java.util.Set;
15
16
/**
17
 * Interface of dictionaries to use for spell checking.
18
 *
19
 * @since 3.0
20
 */
21
public interface ISpellDictionary {
22
23
	/**
24
	 * Returns whether this dictionary accepts new words.
25
	 *
26
	 * @return <code>true</code> if this dictionary accepts new words, <code>false</code> otherwise
27
	 */
28
	public boolean acceptsWords();
29
30
	/**
31
	 * Externalizes the specified word.
32
	 *
33
	 * @param word
34
	 *                   The word to externalize in the dictionary
35
	 */
36
	public void addWord(String word);
37
38
	/**
39
	 * Returns the ranked word proposals for an incorrectly spelled word.
40
	 *
41
	 * @param word
42
	 *                   The word to retrieve the proposals for
43
	 * @param sentence
44
	 *                   <code>true</code> iff the proposals start a new sentence,
45
	 *                   <code>false</code> otherwise
46
	 * @return Array of ranked word proposals
47
	 */
48
	public Set getProposals(String word, boolean sentence);
49
50
	/**
51
	 * Is the specified word correctly spelled?
52
	 *
53
	 * @param word the word to spell check
54
	 * @return <code>true</code> iff this word is correctly spelled, <code>false</code> otherwise
55
	 */
56
	public boolean isCorrect(String word);
57
58
	/**
59
	 * Is the dictionary loaded?
60
	 *
61
	 * @return <code>true</code> iff it is loaded, <code>false</code> otherwise
62
	 */
63
	public boolean isLoaded();
64
65
	/**
66
	 * Empties the dictionary.
67
	 */
68
	public void unload();
69
70
	/**
71
	 * Tells whether to strip non-letters from word boundaries.
72
	 *
73
	 * @param state <code>true</code> if non-letters should be stripped
74
	 * @since 3.3
75
	 */
76
	public void setStripNonLetters(boolean state);
77
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/engine/ISpellEvent.java (-64 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2007 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling.engine;
13
14
import java.util.Set;
15
16
/**
17
 * Event fired by spell checkers.
18
 *
19
 * @since 3.0
20
 */
21
public interface ISpellEvent {
22
23
	/**
24
	 * Returns the begin index of the incorrectly spelled word.
25
	 *
26
	 * @return The begin index of the word
27
	 */
28
	public int getBegin();
29
30
	/**
31
	 * Returns the end index of the incorrectly spelled word.
32
	 *
33
	 * @return The end index of the word
34
	 */
35
	public int getEnd();
36
37
	/**
38
	 * Returns the proposals for the incorrectly spelled word.
39
	 *
40
	 * @return Array of proposals for the word
41
	 */
42
	public Set getProposals();
43
44
	/**
45
	 * Returns the incorrectly spelled word.
46
	 *
47
	 * @return The incorrect word
48
	 */
49
	public String getWord();
50
51
	/**
52
	 * Was the incorrectly spelled word found in the dictionary?
53
	 *
54
	 * @return <code>true</code> iff the word was found, <code>false</code> otherwise
55
	 */
56
	public boolean isMatch();
57
58
	/**
59
	 * Does the incorrectly spelled word start a new sentence?
60
	 *
61
	 * @return <code>true<code> iff the word starts a new sentence, <code>false</code> otherwise
62
	 */
63
	public boolean isStart();
64
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/engine/ISpellEventListener.java (-29 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling.engine;
13
14
15
/**
16
 * Interface for spell event listeners.
17
 *
18
 * @since 3.0
19
 */
20
public interface ISpellEventListener {
21
22
	/**
23
	 * Handles a spell event.
24
	 *
25
	 * @param event
26
	 *                  Event to handle
27
	 */
28
	public void handle(ISpellEvent event);
29
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/engine/LocaleSensitiveSpellDictionary.java (-67 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.ui.text.spelling.engine;
12
13
import java.net.MalformedURLException;
14
import java.net.URL;
15
import java.util.Locale;
16
17
18
/**
19
 * Platform wide read-only locale sensitive dictionary for spell checking.
20
 *
21
 * @since 3.0
22
 */
23
public class LocaleSensitiveSpellDictionary extends AbstractSpellDictionary {
24
25
	/** The locale of this dictionary */
26
	private final Locale fLocale;
27
28
	/** The location of the dictionaries */
29
	private final URL fLocation;
30
31
	/**
32
	 * Creates a new locale sensitive spell dictionary.
33
	 *
34
	 * @param locale
35
	 *                   The locale for this dictionary
36
	 * @param location
37
	 *                   The location of the locale sensitive dictionaries
38
	 */
39
	public LocaleSensitiveSpellDictionary(final Locale locale, final URL location) {
40
		fLocation= location;
41
		fLocale= locale;
42
	}
43
44
	/**
45
	 * Returns the locale of this dictionary.
46
	 *
47
	 * @return The locale of this dictionary
48
	 */
49
	public final Locale getLocale() {
50
		return fLocale;
51
	}
52
53
	/*
54
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary#getURL()
55
	 */
56
	protected final URL getURL() throws MalformedURLException {
57
		return new URL(fLocation, fLocale.toString() + ".dictionary");  //$NON-NLS-1$
58
	}
59
60
	/*
61
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary#getInitialSize()
62
	 * @since 3.6
63
	 */
64
	protected int getInitialSize() {
65
		return 32 * 1024;
66
	}
67
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/engine/PersistentSpellDictionary.java (-97 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *     Benjamin Muskalla <b.muskalla@gmx.net> - [spell checking][implementation] PersistentSpellDictionary closes wrong stream - https://bugs.eclipse.org/bugs/show_bug.cgi?id=236421
11
 *******************************************************************************/
12
package org.eclipse.jdt.internal.ui.text.spelling.engine;
13
14
import java.io.FileOutputStream;
15
import java.io.IOException;
16
import java.net.URL;
17
import java.nio.ByteBuffer;
18
import java.nio.charset.Charset;
19
20
import org.eclipse.jdt.internal.ui.JavaPlugin;
21
22
23
/**
24
 * Persistent modifiable word-list based dictionary.
25
 *
26
 * @since 3.0
27
 */
28
public class PersistentSpellDictionary extends AbstractSpellDictionary {
29
30
	/** The word list location */
31
	private final URL fLocation;
32
33
	/**
34
	 * Creates a new persistent spell dictionary.
35
	 *
36
	 * @param url the URL of the word list for this dictionary
37
	 */
38
	public PersistentSpellDictionary(final URL url) {
39
		fLocation= url;
40
	}
41
42
	/*
43
	 * @see org.eclipse.jdt.ui.text.spelling.engine.AbstractSpellDictionary#acceptsWords()
44
	 */
45
	public boolean acceptsWords() {
46
		return true;
47
	}
48
49
	/*
50
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary#addWord(java.lang.String)
51
	 */
52
	public void addWord(final String word) {
53
		if (isCorrect(word))
54
			return;
55
56
		FileOutputStream fileStream= null;
57
		try {
58
			Charset charset= Charset.forName(getEncoding());
59
			ByteBuffer byteBuffer= charset.encode(word + "\n"); //$NON-NLS-1$
60
			int size= byteBuffer.limit();
61
			final byte[] byteArray;
62
			if (byteBuffer.hasArray())
63
				byteArray= byteBuffer.array();
64
			else {
65
				byteArray= new byte[size];
66
				byteBuffer.get(byteArray);
67
			}
68
69
			fileStream= new FileOutputStream(fLocation.getPath(), true);
70
71
			// Encoding UTF-16 charset writes a BOM. In which case we need to cut it away if the file isn't empty
72
			int bomCutSize= 0;
73
			if (!isEmpty() && "UTF-16".equals(charset.name())) //$NON-NLS-1$
74
				bomCutSize= 2;
75
76
			fileStream.write(byteArray, bomCutSize, size - bomCutSize);
77
		} catch (IOException exception) {
78
			JavaPlugin.log(exception);
79
			return;
80
		} finally {
81
			try {
82
				if (fileStream != null)
83
					fileStream.close();
84
			} catch (IOException e) {
85
			}
86
		}
87
88
		hashWord(word);
89
	}
90
91
	/*
92
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary#getURL()
93
	 */
94
	protected final URL getURL() {
95
		return fLocation;
96
	}
97
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/engine/RankedWordProposal.java (-102 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling.engine;
13
14
/**
15
 * Ranked word proposal for quick fix and content assist.
16
 *
17
 * @since 3.0
18
 */
19
public class RankedWordProposal implements Comparable {
20
21
	/** The word rank */
22
	private int fRank;
23
24
	/** The word text */
25
	private final String fText;
26
27
	/**
28
	 * Creates a new ranked word proposal.
29
	 *
30
	 * @param text
31
	 *                   The text of this proposal
32
	 * @param rank
33
	 *                   The rank of this proposal
34
	 */
35
	public RankedWordProposal(final String text, final int rank) {
36
		fText= text;
37
		fRank= rank;
38
	}
39
40
	/*
41
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
42
	 */
43
	public final int compareTo(Object object) {
44
45
		final RankedWordProposal word= (RankedWordProposal)object;
46
		final int rank= word.getRank();
47
48
		if (fRank < rank)
49
			return -1;
50
51
		if (fRank > rank)
52
			return 1;
53
54
		return 0;
55
	}
56
57
	/*
58
	 * @see java.lang.Object#equals(java.lang.Object)
59
	 */
60
	public final boolean equals(Object object) {
61
62
		if (object instanceof RankedWordProposal)
63
			return object.hashCode() == hashCode();
64
65
		return false;
66
	}
67
68
	/**
69
	 * Returns the rank of the word
70
	 *
71
	 * @return The rank of the word
72
	 */
73
	public final int getRank() {
74
		return fRank;
75
	}
76
77
	/**
78
	 * Returns the text of this word.
79
	 *
80
	 * @return The text of this word
81
	 */
82
	public final String getText() {
83
		return fText;
84
	}
85
86
	/*
87
	 * @see java.lang.Object#hashCode()
88
	 */
89
	public final int hashCode() {
90
		return fText.hashCode();
91
	}
92
93
	/**
94
	 * Sets the rank of the word.
95
	 *
96
	 * @param rank
97
	 *                   The rank to set
98
	 */
99
	public final void setRank(final int rank) {
100
		fRank= rank;
101
	}
102
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/engine/SpellEvent.java (-109 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2007 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.jdt.internal.ui.text.spelling.engine;
13
14
import java.util.Set;
15
16
/**
17
 * Spell event fired for words detected by a spell check iterator.
18
 *
19
 * @since 3.0
20
 */
21
public class SpellEvent implements ISpellEvent {
22
23
	/** The begin index of the word in the spell checkable medium */
24
	private final int fBegin;
25
26
	/** The spell checker that causes the event */
27
	private final ISpellChecker fChecker;
28
29
	/** The end index of the word in the spell checkable medium */
30
	private final int fEnd;
31
32
	/** Was the word found in the dictionary? */
33
	private final boolean fMatch;
34
35
	/** Does the word start a new sentence? */
36
	private final boolean fSentence;
37
38
	/** The word that causes the spell event */
39
	private final String fWord;
40
41
	/**
42
	 * Creates a new spell event.
43
	 *
44
	 * @param checker
45
	 *                   The spell checker that causes the event
46
	 * @param word
47
	 *                   The word that causes the event
48
	 * @param begin
49
	 *                   The begin index of the word in the spell checkable medium
50
	 * @param end
51
	 *                   The end index of the word in the spell checkable medium
52
	 * @param sentence
53
	 *                   <code>true</code> iff the word starts a new sentence,
54
	 *                   <code>false</code> otherwise
55
	 * @param match
56
	 *                   <code>true</code> iff the word was found in the dictionary,
57
	 *                   <code>false</code> otherwise
58
	 */
59
	protected SpellEvent(final ISpellChecker checker, final String word, final int begin, final int end, final boolean sentence, final boolean match) {
60
		fChecker= checker;
61
		fEnd= end;
62
		fBegin= begin;
63
		fWord= word;
64
		fSentence= sentence;
65
		fMatch= match;
66
	}
67
68
	/*
69
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEvent#getBegin()
70
	 */
71
	public final int getBegin() {
72
		return fBegin;
73
	}
74
75
	/*
76
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEvent#getEnd()
77
	 */
78
	public final int getEnd() {
79
		return fEnd;
80
	}
81
82
	/*
83
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEvent#getProposals()
84
	 */
85
	public final Set getProposals() {
86
		return fChecker.getProposals(fWord, fSentence);
87
	}
88
89
	/*
90
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEvent#getWord()
91
	 */
92
	public final String getWord() {
93
		return fWord;
94
	}
95
96
	/*
97
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEvent#isMatch()
98
	 */
99
	public final boolean isMatch() {
100
		return fMatch;
101
	}
102
103
	/*
104
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEvent#isStart()
105
	 */
106
	public final boolean isStart() {
107
		return fSentence;
108
	}
109
}
(-)ui/org/eclipse/jdt/internal/ui/text/spelling/engine/package.html (-84 lines)
Removed Link Here
1
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
2
<html>
3
<head>
4
   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
5
   <meta name="Author" content="IBM">
6
   <meta name="GENERATOR" content="Mozilla/4.51 [en] (WinNT; I) [Netscape]">
7
   <title>Package-level Javadoc</title>
8
</head>
9
<body>
10
Provides the core functionality for spell-checking documents
11
<h2>
12
Package Specification</h2>
13
This package provides the interfaces for the notions of dictionary, edit distance, phonetic hash, 
14
spell event and spell-check iterator. For most of these interfaces a default implementation 
15
for english languages is provided. These implementations can be reused in custom dictionaries or 
16
spell-check iterators, or replaced by more specialized algorithms for a particular group of languages.
17
<h3>
18
Spell Check Engine</h3>
19
The central point to access the spell-checker functionality is the interface <tt>ISpellCheckEngine</tt>. 
20
Implementations of this interface provide support for life-cycle management, registering and unregistering
21
dictionaries, changing the locale of the engine and creating a spell-checker for a specific language.
22
<p>
23
The following steps are needed to obtain a spell-checker for a specific language:
24
<ul>
25
<li>Create an instance of <tt>ISpellCheckEngine</tt>. In this package, no default implementation is provided, 
26
since the management of the dictionary registering and loading is application dependent. Usually, instances 
27
of <tt>ISpellCheckEngine</tt> are implemented as singletons.</li>
28
<li>Create the appropriate dictionaries that should be used during the spell-check process. All dictionaries that 
29
can be registered with <tt>ISpellCheckEngine</tt> must implement the interface <tt>ISpellCheckDictionary</tt>. 
30
For this interface, an abstract implementation is provided in the class <tt>AbstractSpellDictionary</tt>.
31
Depending on the language of the words contained in this dictionary, custom algorithms for the phonetic hash
32
 (<tt>IPhoneticHashProvider</tt>) and the edit distance (<tt>IPhoneticDistanceAlgorithm</tt>) should be implemented 
33
 and registered with the dictionary.</li>
34
 <li>Instances of spell-checkers can now be created by calling <tt>createSpellChecker(Locale)</tt>, where the locale 
35
 denotes the language that the spell-checker should use while executing.</li>
36
</ul>
37
When requesting a new spell-checker with a different locale via <tt>createSpellChecker(Locale)</tt>, the spell-checker is 
38
reconfigured with the new dictionaries. More concretely, the old dictionary is unregistered and a new one registered for the 
39
desired locale is associated with the spell-checker. If no such dictionary is available, no spell-checker is returned and 
40
the locale of the engine is reset to its default locale.
41
<h3>
42
Dictionaries</h3>
43
Dictionaries are the data structures to hold word lists for a particular language. All implementations of dictionaries must 
44
implement the interface <tt>ISpellDictionary</tt>. It provides support for life-cycle management as well as the facility to query 
45
words from the list, add words to the list and get correction proposals for incorrectly spelt words.
46
<p>
47
This package provides a default implementation of a dictionary (<tt>AbstractSpellDictionary</tt>) that uses algorithms 
48
convenient for english languages. <br>
49
Every dictionary needs two kinds of algorithms to be plugged in:
50
<ul>
51
<li>An edit distance algorithm: Edit distance algorithms implement the interface <tt>IPhoneticDistanceAlgorithm</tt>. The algorithm 
52
is used to determine the similarity between two words. This package provides a default implementation for languages using the latin alphabet (<tt>DefaultPhoneticDistanceAlgorithm</tt>). 
53
The default algorithm uses the Levenshtein text edit distance.</li>
54
<li>A hash algorithm: Phonetic hash providers implement the interface <tt>IPhoneticHashProvider</tt>. The purpose of 
55
phonetic hashes is to have a representation of words which allows comparing it to other, similar words. This package provides a default 
56
implementation which is convenient for slavic and english languages. It uses the double metaphone algorithm by published 
57
Lawrence Philips.</li>
58
</ul>
59
By plugging in custom implementations of one or both of these algorithms the abstract implementation <tt>AbstractSpellDictionary</tt> can 
60
be customized to specified languages and alphabets.
61
<h3>
62
Spell Check Iterators</h3>
63
Instances of <tt>ISpellChecker</tt> are usually language-, locale- and medium independent implementations and therefore need an input provider. The 
64
interface <tt>ISpellCheckIterator</tt> serves this purpose by abstracting the tokenizing of text media to a simple iteration. The actual spell-check process 
65
is launched by calling <tt>ISpellChecker#execute(ISpellCheckIterator)</tt>. This method uses the indicated spell-check iterator to determine the 
66
words that are to be spell-checked. This package provides no default implementation of a spell-check iterator.
67
<h3>
68
Event Handling</h3>
69
To communicate the results of a spell-check pass, spell-checkers fire spell events that inform listeners about the status 
70
of a particular word being spell-checked. Instances that are interested in receiving spell events must implement 
71
the interface <tt>ISpellEventListener</tt> and register with the spell-checker before the spell-check process starts.<p>
72
A spell event contains the following information:
73
<ul>
74
<li>The word being spell-checked</li>
75
<li>The begin index of the current word in the text medium</li>
76
<li>The end index in the text medium</li>
77
<li>A flag whether this word was found in one of the registered dictionaries</li>
78
<li>A flag that indicates whether this word starts a new sentence</li>
79
<li>The set of proposals if the word was not correctly spelt. This information is lazily computed.</li>
80
</ul>
81
Spell event listeners are free to handle the events in any way. However, listeners are not allowed to block during 
82
the event handling unless the spell-checking process happens in another thread.
83
</body>
84
</html>
(-)ui/org/eclipse/jdt/ui/PreferenceConstants.java (-1 / +1 lines)
Lines 34-39 Link Here
34
34
35
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
35
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
36
import org.eclipse.ui.texteditor.AbstractTextEditor;
36
import org.eclipse.ui.texteditor.AbstractTextEditor;
37
import org.eclipse.ui.texteditor.spelling.engine.SpellCheckEngine;
37
38
38
import org.eclipse.jdt.core.IClasspathEntry;
39
import org.eclipse.jdt.core.IClasspathEntry;
39
import org.eclipse.jdt.core.IJavaProject;
40
import org.eclipse.jdt.core.IJavaProject;
Lines 52-58 Link Here
52
import org.eclipse.jdt.internal.ui.preferences.formatter.FormatterProfileManager;
53
import org.eclipse.jdt.internal.ui.preferences.formatter.FormatterProfileManager;
53
import org.eclipse.jdt.internal.ui.text.java.CompletionProposalComputerRegistry;
54
import org.eclipse.jdt.internal.ui.text.java.CompletionProposalComputerRegistry;
54
import org.eclipse.jdt.internal.ui.text.java.ProposalSorterRegistry;
55
import org.eclipse.jdt.internal.ui.text.java.ProposalSorterRegistry;
55
import org.eclipse.jdt.internal.ui.text.spelling.SpellCheckEngine;
56
56
57
57
58
/**
58
/**
(-)leaks/org/eclipse/jdt/ui/tests/leaks/JavaLeakTest.java (-1 / +1 lines)
Lines 45-50 Link Here
45
45
46
import org.eclipse.ui.texteditor.AbstractTextEditor;
46
import org.eclipse.ui.texteditor.AbstractTextEditor;
47
import org.eclipse.ui.texteditor.ChainedPreferenceStore;
47
import org.eclipse.ui.texteditor.ChainedPreferenceStore;
48
import org.eclipse.ui.texteditor.spelling.engine.SpellCheckEngine;
48
49
49
import org.eclipse.ui.editors.text.EditorsUI;
50
import org.eclipse.ui.editors.text.EditorsUI;
50
import org.eclipse.ui.editors.text.TextEditor;
51
import org.eclipse.ui.editors.text.TextEditor;
Lines 62-68 Link Here
62
import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
63
import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
63
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
64
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
64
import org.eclipse.jdt.internal.ui.propertiesfileeditor.PropertiesFileEditor;
65
import org.eclipse.jdt.internal.ui.propertiesfileeditor.PropertiesFileEditor;
65
import org.eclipse.jdt.internal.ui.text.spelling.SpellCheckEngine;
66
import org.eclipse.jdt.internal.ui.wizards.JavaProjectWizard;
66
import org.eclipse.jdt.internal.ui.wizards.JavaProjectWizard;
67
import org.eclipse.jdt.internal.ui.wizards.NewClassCreationWizard;
67
import org.eclipse.jdt.internal.ui.wizards.NewClassCreationWizard;
68
import org.eclipse.jdt.internal.ui.wizards.NewInterfaceCreationWizard;
68
import org.eclipse.jdt.internal.ui.wizards.NewInterfaceCreationWizard;
(-).settings/.api_filters (-6 / +13 lines)
Lines 1-5 Link Here
1
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
1
<?xml version="1.0" encoding="UTF-8"?>
2
<component id="org.eclipse.ui.editors" version="2">
2
<component id="org.eclipse.ui.editors" version="2">
3
    <resource path="src/org/eclipse/ui/editors/text/ITextEditorHelpContextIds.java" type="org.eclipse.ui.editors.text.ITextEditorHelpContextIds">
4
        <filter id="571473929">
5
            <message_arguments>
6
                <message_argument value="IAbstractTextEditorHelpContextIds"/>
7
                <message_argument value="ITextEditorHelpContextIds"/>
8
            </message_arguments>
9
        </filter>
10
    </resource>
3
    <resource path="src/org/eclipse/ui/texteditor/DefaultMarkerAnnotationAccess.java" type="org.eclipse.ui.texteditor.DefaultMarkerAnnotationAccess">
11
    <resource path="src/org/eclipse/ui/texteditor/DefaultMarkerAnnotationAccess.java" type="org.eclipse.ui.texteditor.DefaultMarkerAnnotationAccess">
4
        <filter id="643842064">
12
        <filter id="643842064">
5
            <message_arguments>
13
            <message_arguments>
Lines 8-19 Link Here
8
                <message_argument value="getAnnotationTypeHierarchy()"/>
16
                <message_argument value="getAnnotationTypeHierarchy()"/>
9
            </message_arguments>
17
            </message_arguments>
10
        </filter>
18
        </filter>
11
    </resource>
19
        <filter id="1141899266">
12
    <resource path="src/org/eclipse/ui/editors/text/ITextEditorHelpContextIds.java" type="org.eclipse.ui.editors.text.ITextEditorHelpContextIds">
13
        <filter id="571473929">
14
            <message_arguments>
20
            <message_arguments>
15
                <message_argument value="IAbstractTextEditorHelpContextIds"/>
21
                <message_argument value="3.0"/>
16
                <message_argument value="ITextEditorHelpContextIds"/>
22
                <message_argument value="3.6"/>
23
                <message_argument value="getAnnotationTypeHierarchy()"/>
17
            </message_arguments>
24
            </message_arguments>
18
        </filter>
25
        </filter>
19
    </resource>
26
    </resource>
(-)src/org/eclipse/ui/editors/text/TextSourceViewerConfiguration.java (-1 / +1 lines)
Lines 54-62 Link Here
54
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
54
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
55
import org.eclipse.ui.texteditor.AnnotationPreference;
55
import org.eclipse.ui.texteditor.AnnotationPreference;
56
import org.eclipse.ui.texteditor.HyperlinkDetectorRegistry;
56
import org.eclipse.ui.texteditor.HyperlinkDetectorRegistry;
57
import org.eclipse.ui.texteditor.spelling.SpellingCorrectionProcessor;
58
import org.eclipse.ui.texteditor.spelling.SpellingReconcileStrategy;
57
import org.eclipse.ui.texteditor.spelling.SpellingReconcileStrategy;
59
import org.eclipse.ui.texteditor.spelling.SpellingService;
58
import org.eclipse.ui.texteditor.spelling.SpellingService;
59
import org.eclipse.ui.texteditor.spelling.correction.SpellingCorrectionProcessor;
60
60
61
61
62
/**
62
/**
(-)META-INF/MANIFEST.MF (-3 / +8 lines)
Lines 9-30 Link Here
9
Bundle-Localization: plugin
9
Bundle-Localization: plugin
10
Export-Package: 
10
Export-Package: 
11
 org.eclipse.ui.contentassist,
11
 org.eclipse.ui.contentassist,
12
 org.eclipse.ui.internal.texteditor; texteditor="split"; mandatory:="texteditor"; x-friends:="org.eclipse.ui.editors",
12
 org.eclipse.ui.internal.texteditor;texteditor=split;mandatory:=texteditor;x-friends:="org.eclipse.ui.editors",
13
 org.eclipse.ui.internal.texteditor.quickdiff;x-internal:=true,
13
 org.eclipse.ui.internal.texteditor.quickdiff;x-internal:=true,
14
 org.eclipse.ui.internal.texteditor.quickdiff.compare.equivalence;x-internal:=true,
14
 org.eclipse.ui.internal.texteditor.quickdiff.compare.equivalence;x-internal:=true,
15
 org.eclipse.ui.internal.texteditor.rulers;x-internal:=true,
15
 org.eclipse.ui.internal.texteditor.rulers;x-internal:=true,
16
 org.eclipse.ui.internal.texteditor.spelling;x-internal:=true,
16
 org.eclipse.ui.internal.texteditor.spelling;x-internal:=true,
17
 org.eclipse.ui.texteditor; texteditor="split"; mandatory:="texteditor",
17
 org.eclipse.ui.internal.texteditor.spelling.engine;x-internal:=true,
18
 org.eclipse.ui.texteditor;texteditor=split;mandatory:=texteditor,
18
 org.eclipse.ui.texteditor.link,
19
 org.eclipse.ui.texteditor.link,
19
 org.eclipse.ui.texteditor.quickdiff,
20
 org.eclipse.ui.texteditor.quickdiff,
20
 org.eclipse.ui.texteditor.rulers,
21
 org.eclipse.ui.texteditor.rulers,
21
 org.eclipse.ui.texteditor.spelling,
22
 org.eclipse.ui.texteditor.spelling,
23
 org.eclipse.ui.texteditor.spelling.correction,
24
 org.eclipse.ui.texteditor.spelling.engine,
22
 org.eclipse.ui.texteditor.templates
25
 org.eclipse.ui.texteditor.templates
23
Require-Bundle: 
26
Require-Bundle: 
24
 org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)",
27
 org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)",
25
 org.eclipse.compare.core;bundle-version="[3.5.0,4.0.0)",
28
 org.eclipse.compare.core;bundle-version="[3.5.0,4.0.0)",
26
 org.eclipse.core.expressions;bundle-version="[3.4.100,4.0.0)",
29
 org.eclipse.core.expressions;bundle-version="[3.4.100,4.0.0)",
27
 org.eclipse.jface.text;bundle-version="[3.7.0,4.0.0)",
30
 org.eclipse.jface.text;bundle-version="[3.7.0,4.0.0)",
28
 org.eclipse.ui;bundle-version="[3.5.0,4.0.0)"
31
 org.eclipse.ui;bundle-version="[3.5.0,4.0.0)",
32
 org.eclipse.core.resources;bundle-version="3.6.100",
33
 org.eclipse.core.variables;bundle-version="3.2.400"
29
Bundle-RequiredExecutionEnvironment: J2SE-1.4
34
Bundle-RequiredExecutionEnvironment: J2SE-1.4
30
Import-Package: com.ibm.icu.text
35
Import-Package: com.ibm.icu.text
(-)plugin.xml (+10 lines)
Lines 1182-1185 Link Here
1182
         </fontValue>
1182
         </fontValue>
1183
      </fontDefinition>
1183
      </fontDefinition>
1184
   </extension>
1184
   </extension>
1185
   
1186
   <extension point="org.eclipse.ui.workbench.texteditor.spellingEngine">
1187
        <engine
1188
              label="Text spelling engine"
1189
              class="org.eclipse.ui.internal.texteditor.spelling.TextSpellingEngine"
1190
              default="false"
1191
              id="org.eclipse.ui.internal.texteditor.spelling.TextSpellingEngine"
1192
              contentType="org.eclipse.core.runtime.text">
1193
        </engine>
1194
   </extension>
1185
</plugin>
1195
</plugin>
(-)schema/spellingEngine.exsd (-9 / +13 lines)
Lines 1-6 Link Here
1
<?xml version='1.0' encoding='UTF-8'?>
1
<?xml version='1.0' encoding='UTF-8'?>
2
<!-- Schema file written by PDE -->
2
<!-- Schema file written by PDE -->
3
<schema targetNamespace="org.eclipse.ui.workbench.texteditor">
3
<schema targetNamespace="org.eclipse.ui.workbench.texteditor" xmlns="http://www.w3.org/2001/XMLSchema">
4
<annotation>
4
<annotation>
5
      <appInfo>
5
      <appInfo>
6
         <meta.schema plugin="org.eclipse.ui.workbench.texteditor" id="spellingEngine" name="Spelling Engine"/>
6
         <meta.schema plugin="org.eclipse.ui.workbench.texteditor" id="spellingEngine" name="Spelling Engine"/>
Lines 11-16 Link Here
11
   </annotation>
11
   </annotation>
12
12
13
   <element name="extension">
13
   <element name="extension">
14
      <annotation>
15
         <appInfo>
16
            <meta.element />
17
         </appInfo>
18
      </annotation>
14
      <complexType>
19
      <complexType>
15
         <sequence>
20
         <sequence>
16
            <element ref="engine" minOccurs="1" maxOccurs="unbounded"/>
21
            <element ref="engine" minOccurs="1" maxOccurs="unbounded"/>
Lines 79-84 Link Here
79
               </documentation>
84
               </documentation>
80
            </annotation>
85
            </annotation>
81
         </attribute>
86
         </attribute>
87
         <attribute name="contentType" type="string">
88
            <annotation>
89
               <documentation>
90
                  
91
               </documentation>
92
            </annotation>
93
         </attribute>
82
         <attribute name="default" type="boolean">
94
         <attribute name="default" type="boolean">
83
            <annotation>
95
            <annotation>
84
               <documentation>
96
               <documentation>
Lines 130-143 Link Here
130
      </documentation>
142
      </documentation>
131
   </annotation>
143
   </annotation>
132
144
133
   <annotation>
134
      <appInfo>
135
         <meta.section type="apiInfo"/>
136
      </appInfo>
137
      <documentation>
138
         
139
      </documentation>
140
   </annotation>
141
145
142
   <annotation>
146
   <annotation>
143
      <appInfo>
147
      <appInfo>
(-)src/org/eclipse/ui/internal/texteditor/TextEditorPlugin.java (-1 / +19 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 19-25 Link Here
19
import org.eclipse.core.runtime.Assert;
19
import org.eclipse.core.runtime.Assert;
20
import org.eclipse.core.runtime.IRegistryChangeEvent;
20
import org.eclipse.core.runtime.IRegistryChangeEvent;
21
import org.eclipse.core.runtime.IRegistryChangeListener;
21
import org.eclipse.core.runtime.IRegistryChangeListener;
22
import org.eclipse.core.runtime.IStatus;
22
import org.eclipse.core.runtime.Platform;
23
import org.eclipse.core.runtime.Platform;
24
import org.eclipse.core.runtime.Status;
23
25
24
import org.eclipse.jface.action.IAction;
26
import org.eclipse.jface.action.IAction;
25
27
Lines 197-200 Link Here
197
	public SpellingEngineRegistry getSpellingEngineRegistry() {
199
	public SpellingEngineRegistry getSpellingEngineRegistry() {
198
		return fSpellingEngineRegistry;
200
		return fSpellingEngineRegistry;
199
	}
201
	}
202
203
	public static String getPluginId() {
204
		return PLUGIN_ID;
205
	}
206
207
	public static void log(IStatus status) {
208
		getDefault().getLog().log(status);
209
	}
210
211
	public static void logErrorMessage(String message) {
212
		log(new Status(IStatus.ERROR, getPluginId(), message, null));
213
	}
214
215
	public static void log(Throwable e) {
216
		log(new Status(IStatus.ERROR, getPluginId(), "Internal Error", e));
217
	}
200
}
218
}
(-)src/org/eclipse/ui/internal/texteditor/spelling/IProblemLocation.java (+76 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.internal.texteditor.spelling;
12
13
14
15
/**
16
 * Problem information for quick fix and quick assist processors.
17
 * <p>
18
 * Note: this interface is not intended to be implemented.
19
 * </p>
20
 *
21
 * @since 3.0
22
 *
23
 * @noimplement This interface is not intended to be implemented by clients.
24
 * @noextend This interface is not intended to be extended by clients.
25
 */
26
/*
27
 * TODO: copied from JDT and slightly modified, could probably remain here as the text editor should also have a notion of problem location
28
 * 
29
 */
30
public interface IProblemLocation {
31
32
	/**
33
	 * Returns the start offset of the problem.
34
	 *
35
	 * @return the start offset of the problem
36
	 */
37
	int getOffset();
38
39
	/**
40
	 * Returns the length of the problem.
41
	 *
42
	 * @return the length of the problem
43
	 */
44
	int getLength();
45
46
	/**
47
	 * Returns the marker type of this problem.
48
	 *
49
	 * @return The marker type of the problem.
50
	 * @since 3.2
51
	 */
52
	String getMarkerType();
53
54
	/**
55
	 * Returns the id of problem. Note that problem ids are defined per problem marker type.
56
	 * See {@link org.eclipse.jdt.core.compiler.IProblem} for id definitions for problems of type
57
	 * <code>org.eclipse.jdt.core.problem</code> and <code>org.eclipse.jdt.core.task</code>.
58
	 *
59
	 * @return The id of the problem.
60
	 */
61
	int getProblemId();
62
63
	/**
64
	 * Returns the original arguments recorded into the problem.
65
	 *
66
	 * @return String[] Returns the problem arguments.
67
	 */
68
	String[] getProblemArguments();
69
70
	/**
71
	 * Returns if the problem has error severity.
72
	 *
73
	 * @return <code>true</code> if the problem has error severity
74
	 */
75
	boolean isError();
76
}
(-)src/org/eclipse/ui/internal/texteditor/spelling/ISpellingCompletionProposalComputer.java (+72 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.internal.texteditor.spelling;
12
13
import org.eclipse.core.runtime.IProgressMonitor;
14
15
/**
16
 * Computes completions and context information displayed by the Java editor content assistant.
17
 * Contributions to the <tt>org.eclipse.jdt.ui.javaCompletionProposalComputer</tt> extension point
18
 * must implement this interface.
19
 *
20
 * @since 3.2
21
 */
22
23
/*
24
 * TODO: Apparently this is not supported. See Javadoc of WordCompletionProposalComputer
25
 */
26
public interface ISpellingCompletionProposalComputer {
27
	/**
28
	 * Informs the computer that a content assist session has started. This call will always be
29
	 * followed by a {@link #sessionEnded()} call, but not necessarily by calls to
30
	 * {@linkplain #computeCompletionProposals(ContentAssistInvocationContext, IProgressMonitor) computeCompletionProposals}
31
	 * or
32
	 * {@linkplain #computeContextInformation(ContentAssistInvocationContext, IProgressMonitor) computeContextInformation}.
33
	 */
34
	void sessionStarted();
35
36
	/**
37
	 * Returns a list of completion proposals valid at the given invocation context.
38
	 *
39
	 * @param context the context of the content assist invocation
40
	 * @param monitor a progress monitor to report progress. The monitor is private to this
41
	 *        invocation, i.e. there is no need for the receiver to spawn a sub monitor.
42
	 * @return a list of completion proposals (element type: {@link ICompletionProposal})
43
	 */
44
	//List computeCompletionProposals(ContentAssistInvocationContext context, IProgressMonitor monitor);
45
46
	/**
47
	 * Returns context information objects valid at the given invocation context.
48
	 *
49
	 * @param context the context of the content assist invocation
50
	 * @param monitor a progress monitor to report progress. The monitor is private to this
51
	 *        invocation, i.e. there is no need for the receiver to spawn a sub monitor.
52
	 * @return a list of context information objects (element type: {@link IContextInformation})
53
	 */
54
	//List computeContextInformation(ContentAssistInvocationContext context, IProgressMonitor monitor);
55
56
	/**
57
	 * Returns the reason why this computer was unable to produce any completion proposals or
58
	 * context information.
59
	 *
60
	 * @return an error message or <code>null</code> if no error occurred
61
	 */
62
	String getErrorMessage();
63
64
	/**
65
	 * Informs the computer that a content assist session has ended. This call will always be after
66
	 * any calls to
67
	 * {@linkplain #computeCompletionProposals(ContentAssistInvocationContext, IProgressMonitor) computeCompletionProposals}
68
	 * and
69
	 * {@linkplain #computeContextInformation(ContentAssistInvocationContext, IProgressMonitor) computeContextInformation}.
70
	 */
71
	void sessionEnded();
72
}
(-)src/org/eclipse/ui/internal/texteditor/spelling/Messages.java (+33 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.internal.texteditor.spelling;
12
13
import com.ibm.icu.text.MessageFormat;
14
15
/**
16
 * Helper class to format message strings.
17
 *
18
 * @since 3.1
19
 */
20
public class Messages {
21
22
	public static String format(String message, Object object) {
23
		return MessageFormat.format(message, new Object[] { object});
24
	}
25
26
	public static String format(String message, Object[] objects) {
27
		return MessageFormat.format(message, objects);
28
	}
29
30
	private Messages() {
31
		// Not for instantiation
32
	}
33
}
(-)src/org/eclipse/ui/internal/texteditor/spelling/NoCompletionsProposal.java (-72 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.internal.texteditor.spelling;
12
13
import org.eclipse.swt.graphics.Image;
14
import org.eclipse.swt.graphics.Point;
15
16
import org.eclipse.jface.text.IDocument;
17
import org.eclipse.jface.text.contentassist.ICompletionProposal;
18
import org.eclipse.jface.text.contentassist.IContextInformation;
19
20
/**
21
 * Proposal telling that there are no proposals available.
22
 * <p>
23
 * Applying this proposal does nothing.
24
 * </p>
25
 *
26
 * @since 3.3
27
 */
28
public final class NoCompletionsProposal implements ICompletionProposal {
29
30
	/*
31
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(org.eclipse.jface.text.IDocument)
32
	 */
33
	public void apply(IDocument document) {
34
		// do nothing
35
	}
36
37
	/*
38
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo()
39
	 */
40
	public String getAdditionalProposalInfo() {
41
		return null;
42
	}
43
44
	/*
45
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getContextInformation()
46
	 */
47
	public IContextInformation getContextInformation() {
48
		return null;
49
	}
50
51
	/*
52
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString()
53
	 */
54
	public String getDisplayString() {
55
			return SpellingMessages.NoCompletionsProposal_displayString;
56
		}
57
58
	/*
59
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage()
60
	 */
61
	public Image getImage() {
62
		return null;
63
	}
64
65
	/*
66
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getSelection(org.eclipse.jface.text.IDocument)
67
	 */
68
	public Point getSelection(IDocument document) {
69
		return null;
70
	}
71
72
}
(-)src/org/eclipse/ui/internal/texteditor/spelling/SpellingEngineRegistry.java (-1 / +34 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2009 IBM Corporation and others.
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 12-23 Link Here
12
package org.eclipse.ui.internal.texteditor.spelling;
12
package org.eclipse.ui.internal.texteditor.spelling;
13
13
14
import java.util.ArrayList;
14
import java.util.ArrayList;
15
import java.util.Collection;
15
import java.util.HashMap;
16
import java.util.HashMap;
17
import java.util.Iterator;
16
import java.util.List;
18
import java.util.List;
17
import java.util.Map;
19
import java.util.Map;
18
20
19
import org.eclipse.core.runtime.IConfigurationElement;
21
import org.eclipse.core.runtime.IConfigurationElement;
20
import org.eclipse.core.runtime.Platform;
22
import org.eclipse.core.runtime.Platform;
23
import org.eclipse.core.runtime.content.IContentType;
21
24
22
import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
25
import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
23
26
Lines 64-69 Link Here
64
	}
67
	}
65
68
66
	/**
69
	/**
70
	 * Returns the descriptor with the given contentType or <code>null</code> if none could be
71
	 * found.
72
	 * 
73
	 * @param contentType the content type
74
	 * 
75
	 * @return the descriptor with the given content type or <code>null</code>
76
	 */
77
	public SpellingEngineDescriptor getDescriptor(IContentType contentType) {
78
		ensureExtensionsLoaded();
79
		Collection descriptors= fDescriptorsMap.values(); // TODO: better way ?
80
81
		for (Iterator iterator= descriptors.iterator(); iterator.hasNext();) {
82
			SpellingEngineDescriptor descriptor= (SpellingEngineDescriptor)iterator.next();
83
			if (descriptor.getContentType() == null) { //'all content type'
84
				return descriptor;
85
			}
86
		}
87
88
		// there is no 'all content type' engine
89
		for (Iterator iterator= descriptors.iterator(); iterator.hasNext();) {
90
			SpellingEngineDescriptor descriptor= (SpellingEngineDescriptor)iterator.next();
91
			IContentType descriptorContentType= Platform.getContentTypeManager().getContentType(descriptor.getContentType());
92
			if (descriptorContentType != null && descriptorContentType.equals(contentType)) {
93
				return descriptor;
94
			}
95
		}
96
		return null;
97
	}
98
99
	/**
67
	 * Returns the default descriptor.
100
	 * Returns the default descriptor.
68
	 *
101
	 *
69
	 * @return the default descriptor
102
	 * @return the default descriptor
(-)src/org/eclipse/ui/internal/texteditor/spelling/SpellingMessages.java (-7 / +20 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 17-36 Link Here
17
 *
17
 *
18
 * @since 3.1
18
 * @since 3.1
19
 */
19
 */
20
final class SpellingMessages extends NLS {
20
public final class SpellingMessages extends NLS {
21
21
22
	private static final String BUNDLE_NAME= SpellingMessages.class.getName();
22
	private static final String BUNDLE_NAME= SpellingMessages.class.getName();
23
23
24
	private SpellingMessages() {
24
	private SpellingMessages() {
25
		// Do not instantiate
25
		// Do not instantiate
26
	}
26
	}
27
27
	
28
	static {
29
		NLS.initializeMessages(BUNDLE_NAME, SpellingMessages.class);
30
	}
28
31
29
	public static String EmptySpellingPreferenceBlock_emptyCaption;
32
	public static String EmptySpellingPreferenceBlock_emptyCaption;
30
	public static String NoCompletionsProposal_displayString;
33
	public static String NoCompletionsProposal_displayString;
31
34
32
35
	public static String Spelling_error_label;
33
	static {
36
	public static String Spelling_correct_label;
34
		NLS.initializeMessages(BUNDLE_NAME, SpellingMessages.class);
37
	public static String Spelling_add_info;
35
	}
38
	public static String Spelling_add_label;
39
	public static String Spelling_add_askToConfigure_title;
40
	public static String Spelling_add_askToConfigure_question;
41
	public static String Spelling_add_askToConfigure_ignoreMessage;
42
	public static String Spelling_ignore_info;
43
	public static String Spelling_ignore_label;
44
	public static String Spelling_disable_label;
45
	public static String Spelling_disable_info;
46
	public static String Spelling_case_label;
47
	public static String Spelling_error_case_label;
48
	public static String AbstractSpellingDictionary_encodingError;
36
}
49
}
(-)src/org/eclipse/ui/internal/texteditor/spelling/SpellingMessages.properties (+16 lines)
Lines 12-14 Link Here
12
EmptySpellingPreferenceBlock_emptyCaption=
12
EmptySpellingPreferenceBlock_emptyCaption=
13
13
14
NoCompletionsProposal_displayString= No suggestions available
14
NoCompletionsProposal_displayString= No suggestions available
15
16
Spelling_error_label=The word ''{0}'' is not correctly spelled
17
Spelling_correct_label=Change to ''{0}''
18
Spelling_add_info=Adds the word ''{0}'' to the dictionary
19
Spelling_add_label=Add ''{0}'' to dictionary
20
Spelling_add_askToConfigure_title=Missing User Dictionary
21
Spelling_add_askToConfigure_question=A user dictionary is needed to add words.\nDo you want to configure it now?\n
22
Spelling_add_askToConfigure_ignoreMessage= &Do not show 'Add word' proposals if user dictionary is missing
23
Spelling_ignore_info=Ignores ''{0}'' during the current session
24
Spelling_ignore_label=Ignore ''{0}'' during the current session
25
Spelling_case_label=Change to upper case
26
Spelling_disable_label=Disable spell checking
27
Spelling_disable_info=Disables spell checking.
28
Spelling_error_case_label= The word ''{0}'' should have an initial upper case letter
29
AbstractSpellingDictionary_encodingError= Could not read: ''{0}'', where the bad characters are replaced by ''{1}''. Check the encoding of the spelling dictionary ({2}).
30
(-)src/org/eclipse/ui/internal/texteditor/spelling/TextSpellingEngine.java (+45 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.internal.texteditor.spelling;
13
14
import org.eclipse.core.runtime.IProgressMonitor;
15
16
import org.eclipse.jface.text.IDocument;
17
import org.eclipse.jface.text.IRegion;
18
19
import org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector;
20
import org.eclipse.ui.texteditor.spelling.SpellCheckIterator;
21
import org.eclipse.ui.texteditor.spelling.engine.ISpellChecker;
22
import org.eclipse.ui.texteditor.spelling.engine.SpellingEngine;
23
24
/**
25
 * Text spelling engine
26
 *
27
 * @since 3.1
28
 */
29
public class TextSpellingEngine extends SpellingEngine {
30
31
	/*
32
	 * @see org.eclipse.jdt.internal.ui.text.spelling.SpellingEngine#check(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IRegion[], org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker, org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector, org.eclipse.core.runtime.IProgressMonitor)
33
	 */
34
	protected void check(IDocument document, IRegion[] regions, ISpellChecker checker, ISpellingProblemCollector collector, IProgressMonitor monitor) {
35
		SpellEventListener listener= new SpellEventListener(collector, document);
36
		for (int i= 0; i < regions.length; i++) {
37
			if (monitor != null && monitor.isCanceled())
38
				return;
39
			//TODO : Commented to get it working
40
			/*if (listener.isProblemsThresholdReached())
41
				return;*/
42
			checker.execute(listener, new SpellCheckIterator(document, regions[i], checker.getLocale()));
43
		}
44
	}
45
}
(-)src/org/eclipse/ui/internal/texteditor/spelling/WordCompletionProposalComputer.java (+125 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.internal.texteditor.spelling;
13
14
15
/**
16
 * Content assist processor to complete words.
17
 * <strong>Note:</strong> This is currently not supported because the spelling engine
18
 * cannot return word proposals but only correction proposals.
19
 * <p>
20
 * If we enable this again we must register the computer in <code>plugin.xml</code>:
21
 * <pre>
22
 * </pre>
23
 * </p>
24
 *
25
 * @since 3.0
26
 */
27
/*
28
 * TODO: the Javadoc says that this is not supported?? What is word completion then Alt+/. Anyway leave it for now
29
 */
30
31
32
33
/*public final class WordCompletionProposalComputer implements IJavaCompletionProposalComputer {
34
35
	*//** The prefix rank shift */
36
/*
37
private static final int PREFIX_RANK_SHIFT= 500;
38
39
40
* @see org.eclipse.jface.text.contentassist.ICompletionProposalComputer#computeCompletionProposals(org.eclipse.jface.text.contentassist.TextContentAssistInvocationContext, org.eclipse.core.runtime.IProgressMonitor)
41
42
public List computeCompletionProposals(ContentAssistInvocationContext context, IProgressMonitor monitor) {
43
if (contributes()) {
44
try {
45
IDocument document= context.getDocument();
46
final int offset= context.getInvocationOffset();
47
48
final IRegion region= document.getLineInformationOfOffset(offset);
49
final String content= document.get(region.getOffset(), region.getLength());
50
51
int index= offset - region.getOffset() - 1;
52
while (index >= 0 && Character.isLetter(content.charAt(index)))
53
index--;
54
55
final int start= region.getOffset() + index + 1;
56
final String candidate= content.substring(index + 1, offset - region.getOffset());
57
58
if (candidate.length() > 0) {
59
60
final ISpellCheckEngine engine= SpellCheckEngine.getInstance();
61
final ISpellChecker checker= engine.getSpellChecker();
62
63
if (checker != null) {
64
65
final List proposals= new ArrayList(checker.getProposals(candidate, Character.isUpperCase(candidate.charAt(0))));
66
final List result= new ArrayList(proposals.size());
67
68
for (Iterator it= proposals.iterator(); it.hasNext();) {
69
RankedWordProposal word= (RankedWordProposal) it.next();
70
String text= word.getText();
71
if (text.startsWith(candidate))
72
word.setRank(word.getRank() + PREFIX_RANK_SHIFT);
73
74
result.add(new JavaCompletionProposal(text, start, candidate.length(), JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_RENAME), text, word.getRank()) {
75
76
* @see org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposal#validate(org.eclipse.jface.text.IDocument, int, org.eclipse.jface.text.DocumentEvent)
77
78
public boolean validate(IDocument doc, int validate_offset, DocumentEvent event) {
79
return offset == validate_offset;
80
}
81
});
82
}
83
84
return result;
85
}
86
}
87
} catch (BadLocationException exception) {
88
// log & ignore
89
TextEditorPlugin.log(exception);
90
}
91
}
92
return Collections.EMPTY_LIST;
93
}
94
95
private boolean contributes() {
96
return PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.SPELLING_ENABLE_CONTENTASSIST);
97
}
98
99
100
* @see org.eclipse.jface.text.contentassist.ICompletionProposalComputer#computeContextInformation(org.eclipse.jface.text.contentassist.TextContentAssistInvocationContext, org.eclipse.core.runtime.IProgressMonitor)
101
102
public List computeContextInformation(ContentAssistInvocationContext context, IProgressMonitor monitor) {
103
return Collections.EMPTY_LIST;
104
}
105
106
107
* @see org.eclipse.jface.text.contentassist.ICompletionProposalComputer#getErrorMessage()
108
109
public String getErrorMessage() {
110
return null; // no error message available
111
}
112
113
114
* @see org.eclipse.jdt.ui.text.java.IJavaCompletionProposalComputer#sessionStarted()
115
116
public void sessionStarted() {
117
}
118
119
120
* @see org.eclipse.jdt.ui.text.java.IJavaCompletionProposalComputer#sessionEnded()
121
122
public void sessionEnded() {
123
}
124
}
125
*/
(-)src/org/eclipse/ui/internal/texteditor/spelling/WordQuickFixProcessor.java (+158 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.internal.texteditor.spelling;
12
13
import java.util.ArrayList;
14
import java.util.Collections;
15
import java.util.List;
16
17
import org.eclipse.core.runtime.CoreException;
18
19
import org.eclipse.jface.text.contentassist.ICompletionProposal;
20
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
21
import org.eclipse.jface.text.quickassist.IQuickAssistProcessor;
22
import org.eclipse.jface.text.source.Annotation;
23
import org.eclipse.jface.text.source.ISourceViewer;
24
import org.eclipse.jface.text.source.TextInvocationContext;
25
26
import org.eclipse.ui.texteditor.spelling.PreferenceConstants;
27
import org.eclipse.ui.texteditor.spelling.SpellingAnnotation;
28
import org.eclipse.ui.texteditor.spelling.correction.AddWordProposal;
29
import org.eclipse.ui.texteditor.spelling.correction.ChangeCaseProposal;
30
import org.eclipse.ui.texteditor.spelling.correction.DisableSpellCheckingProposal;
31
import org.eclipse.ui.texteditor.spelling.correction.IHtmlTagConstants;
32
import org.eclipse.ui.texteditor.spelling.correction.IJavaDocTagConstants;
33
import org.eclipse.ui.texteditor.spelling.correction.ISpellingCompletionProposal;
34
import org.eclipse.ui.texteditor.spelling.correction.RankedWordProposal;
35
import org.eclipse.ui.texteditor.spelling.correction.WordCorrectionProposal;
36
import org.eclipse.ui.texteditor.spelling.correction.WordIgnoreProposal;
37
import org.eclipse.ui.texteditor.spelling.engine.ISpellCheckEngine;
38
import org.eclipse.ui.texteditor.spelling.engine.ISpellChecker;
39
import org.eclipse.ui.texteditor.spelling.engine.SpellCheckEngine;
40
41
/**
42
 * Quick fix processor for incorrectly spelled words.
43
 *
44
 * @since 3.0
45
 */
46
public class WordQuickFixProcessor implements IQuickAssistProcessor {
47
48
	//TODO: copied from JavaSpellingReconcileStrategy, will most definitely not work as it would need to be hooked in other places as well
49
	public static final int SPELLING_PROBLEM_ID= 0x80000000;
50
51
	/**
52
	 * Creates a new word quick fix processor.
53
	 */
54
	public WordQuickFixProcessor() {
55
		// For extension point
56
	}
57
58
	/*
59
	 * @see org.eclipse.jdt.ui.text.java.IQuickFixProcessor#getCorrections(org.eclipse.jdt.ui.text.java.IInvocationContext,org.eclipse.jdt.ui.text.java.IProblemLocation[])
60
	 */
61
	private ISpellingCompletionProposal[] getCorrections(IQuickAssistInvocationContext invocationContext, IProblemLocation[] locations) throws CoreException {
62
63
		final int threshold= PreferenceConstants.getPreferenceStore().getInt(PreferenceConstants.SPELLING_PROPOSAL_THRESHOLD);
64
65
		int size= 0;
66
		List proposals= null;
67
		String[] arguments= null;
68
69
		IProblemLocation location= null;
70
		RankedWordProposal proposal= null;
71
		ISpellingCompletionProposal[] result= null;
72
73
		boolean fixed= false;
74
		boolean match= false;
75
		boolean sentence= false;
76
77
		final ISpellCheckEngine engine= SpellCheckEngine.getInstance();
78
		final ISpellChecker checker= engine.getSpellChecker();
79
80
		if (checker != null) {
81
82
			for (int index= 0; index < locations.length; index++) {
83
				location= locations[index];
84
				
85
				ISourceViewer sourceViewer= null;
86
				if (invocationContext != null)
87
					sourceViewer= invocationContext.getSourceViewer();
88
				IQuickAssistInvocationContext context= new TextInvocationContext(sourceViewer, location.getOffset(), location.getLength());
89
90
				if (location.getProblemId() == SPELLING_PROBLEM_ID) {
91
92
					arguments= location.getProblemArguments();
93
					if (arguments != null && arguments.length > 4) {
94
95
						sentence= Boolean.valueOf(arguments[3]).booleanValue();
96
						match= Boolean.valueOf(arguments[4]).booleanValue();
97
						fixed= arguments[0].charAt(0) == IHtmlTagConstants.HTML_TAG_PREFIX || arguments[0].charAt(0) == IJavaDocTagConstants.JAVADOC_TAG_PREFIX;
98
99
						if ((sentence && match) && !fixed)
100
							result= new ISpellingCompletionProposal[] { new ChangeCaseProposal(arguments, location.getOffset(), location.getLength(), context, engine.getLocale()) };
101
						else {
102
103
							proposals= new ArrayList(checker.getProposals(arguments[0], sentence));
104
							size= proposals.size();
105
106
							if (threshold > 0 && size > threshold) {
107
108
								Collections.sort(proposals);
109
								proposals= proposals.subList(size - threshold - 1, size - 1);
110
								size= proposals.size();
111
							}
112
113
							boolean extendable= !fixed ? (checker.acceptsWords() || AddWordProposal.canAskToConfigure()) : false;
114
							result= new ISpellingCompletionProposal[size + (extendable ? 3 : 2)];
115
116
							for (index= 0; index < size; index++) {
117
118
								proposal= (RankedWordProposal)proposals.get(index);
119
								result[index]= new WordCorrectionProposal(proposal.getText(), arguments, location.getOffset(), location.getLength(), context, proposal.getRank());
120
							}
121
122
							if (extendable)
123
								result[index++]= new AddWordProposal(arguments[0], context);
124
125
							result[index++]= new WordIgnoreProposal(arguments[0], context);
126
							result[index++]= new DisableSpellCheckingProposal(context);
127
						}
128
						break;
129
					}
130
				}
131
			}
132
		}
133
		return result;
134
	}
135
136
	public String getErrorMessage() {
137
		// TODO Auto-generated method stub
138
		return null;
139
	}
140
141
	public boolean canFix(Annotation annotation) {
142
		return annotation != null && SpellingAnnotation.TYPE.equals(annotation.getType());
143
	}
144
145
	public boolean canAssist(IQuickAssistInvocationContext invocationContext) {
146
		return false;
147
	}
148
149
	public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationContext invocationContext) {
150
		try {
151
			return getCorrections(invocationContext, null);
152
		} catch (CoreException e) {
153
			// TODO Auto-generated catch block
154
			e.printStackTrace();
155
		}
156
		return null;
157
	}
158
}
(-)src/org/eclipse/ui/internal/texteditor/spelling/engine/DefaultPhoneticDistanceAlgorithm.java (+103 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2007 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.internal.texteditor.spelling.engine;
13
14
/**
15
 * Default phonetic distance algorithm for English words.
16
 * <p>
17
 * This algorithm implements the Levenshtein text edit distance.
18
 * </p>
19
 *
20
 * @since 3.0
21
 */
22
public final class DefaultPhoneticDistanceAlgorithm implements IPhoneticDistanceAlgorithm {
23
24
	/** The change case cost */
25
	public static final int COST_CASE= 10;
26
27
	/** The insert character cost */
28
	public static final int COST_INSERT= 95;
29
30
	/** The remove character cost */
31
	public static final int COST_REMOVE= 95;
32
33
	/** The substitute characters cost */
34
	public static final int COST_SUBSTITUTE= 100;
35
36
	/** The swap characters cost */
37
	public static final int COST_SWAP= 90;
38
39
	/*
40
	 * @see org.eclipse.spelling.done.IPhoneticDistanceAlgorithm#getDistance(java.lang.String,java.lang.String)
41
	 */
42
	public final int getDistance(final String from, final String to) {
43
44
		final char[] first= (" " + from).toCharArray(); //$NON-NLS-1$
45
		final char[] second= (" " + to).toCharArray(); //$NON-NLS-1$
46
47
		final int rows= first.length;
48
		final int columns= second.length;
49
50
		final int[][] metric= new int[rows][columns];
51
		for (int column= 1; column < columns; column++)
52
			metric[0][column]= metric[0][column - 1] + COST_REMOVE;
53
54
		for (int row= 1; row < rows; row++)
55
			metric[row][0]= metric[row - 1][0] + COST_INSERT;
56
57
		char source, target;
58
59
		int swap= Integer.MAX_VALUE;
60
		int change= Integer.MAX_VALUE;
61
62
		int minimum, diagonal, insert, remove;
63
		for (int row= 1; row < rows; row++) {
64
65
			source= first[row];
66
			for (int column= 1; column < columns; column++) {
67
68
				target= second[column];
69
				diagonal= metric[row - 1][column - 1];
70
71
				if (source == target) {
72
					metric[row][column]= diagonal;
73
					continue;
74
				}
75
76
				change= Integer.MAX_VALUE;
77
				if (Character.toLowerCase(source) == Character.toLowerCase(target))
78
					change= COST_CASE + diagonal;
79
80
				swap= Integer.MAX_VALUE;
81
				if (row != 1 && column != 1 && source == second[column - 1] && first[row - 1] == target)
82
					swap= COST_SWAP + metric[row - 2][column - 2];
83
84
				minimum= COST_SUBSTITUTE + diagonal;
85
				if (swap < minimum)
86
					minimum= swap;
87
88
				remove= metric[row][column - 1];
89
				if (COST_REMOVE + remove < minimum)
90
					minimum= COST_REMOVE + remove;
91
92
				insert= metric[row - 1][column];
93
				if (COST_INSERT + insert < minimum)
94
					minimum= COST_INSERT + insert;
95
				if (change < minimum)
96
					minimum= change;
97
98
				metric[row][column]= minimum;
99
			}
100
		}
101
		return metric[rows - 1][columns - 1];
102
	}
103
}
(-)src/org/eclipse/ui/internal/texteditor/spelling/engine/DefaultPhoneticHashProvider.java (+683 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.internal.texteditor.spelling.engine;
13
14
/**
15
 * Default phonetic hash provider for english languages.
16
 * <p>
17
 * This algorithm uses an adapted version double metaphone algorithm by
18
 * Lawrence Philips.
19
 * <p>
20
 *
21
 * @since 3.0
22
 */
23
public final class DefaultPhoneticHashProvider implements IPhoneticHashProvider {
24
25
	private static final String[] meta01= { "ACH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
26
	private static final String[] meta02= { "BACHER", "MACHER", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
27
	private static final String[] meta03= { "CAESAR", "" }; //$NON-NLS-1$ //$NON-NLS-2$
28
	private static final String[] meta04= { "CHIA", "" }; //$NON-NLS-1$ //$NON-NLS-2$
29
	private static final String[] meta05= { "CH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
30
	private static final String[] meta06= { "CHAE", "" }; //$NON-NLS-1$ //$NON-NLS-2$
31
	private static final String[] meta07= { "HARAC", "HARIS", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
32
	private static final String[] meta08= { "HOR", "HYM", "HIA", "HEM", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
33
	private static final String[] meta09= { "CHORE", "" }; //$NON-NLS-1$ //$NON-NLS-2$
34
	private static final String[] meta10= { "VAN ", "VON ", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
35
	private static final String[] meta11= { "SCH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
36
	private static final String[] meta12= { "ORCHES", "ARCHIT", "ORCHID", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
37
	private static final String[] meta13= { "T", "S", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
38
	private static final String[] meta14= { "A", "O", "U", "E", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
39
	private static final String[] meta15= { "L", "R", "N", "M", "B", "H", "F", "V", "W", " ", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$
40
	private static final String[] meta16= { "MC", "" }; //$NON-NLS-1$ //$NON-NLS-2$
41
	private static final String[] meta17= { "CZ", "" }; //$NON-NLS-1$ //$NON-NLS-2$
42
	private static final String[] meta18= { "WICZ", "" }; //$NON-NLS-1$ //$NON-NLS-2$
43
	private static final String[] meta19= { "CIA", "" }; //$NON-NLS-1$ //$NON-NLS-2$
44
	private static final String[] meta20= { "CC", "" }; //$NON-NLS-1$ //$NON-NLS-2$
45
	private static final String[] meta21= { "I", "E", "H", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
46
	private static final String[] meta22= { "HU", "" }; //$NON-NLS-1$ //$NON-NLS-2$
47
	private static final String[] meta23= { "UCCEE", "UCCES", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
48
	private static final String[] meta24= { "CK", "CG", "CQ", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
49
	private static final String[] meta25= { "CI", "CE", "CY", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
50
	private static final String[] meta26= { "GN", "KN", "PN", "WR", "PS", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
51
	private static final String[] meta27= { " C", " Q", " G", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
52
	private static final String[] meta28= { "C", "K", "Q", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
53
	private static final String[] meta29= { "CE", "CI", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
54
	private static final String[] meta30= { "DG", "" }; //$NON-NLS-1$ //$NON-NLS-2$
55
	private static final String[] meta31= { "I", "E", "Y", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
56
	private static final String[] meta32= { "DT", "DD", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
57
	private static final String[] meta33= { "B", "H", "D", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
58
	private static final String[] meta34= { "B", "H", "D", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
59
	private static final String[] meta35= { "B", "H", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
60
	private static final String[] meta36= { "C", "G", "L", "R", "T", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
61
	private static final String[] meta37= { "EY", "" }; //$NON-NLS-1$ //$NON-NLS-2$
62
	private static final String[] meta38= { "LI", "" }; //$NON-NLS-1$ //$NON-NLS-2$
63
	private static final String[] meta39= { "ES", "EP", "EB", "EL", "EY", "IB", "IL", "IN", "IE", "EI", "ER", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$
64
	private static final String[] meta40= { "ER", "" }; //$NON-NLS-1$ //$NON-NLS-2$
65
	private static final String[] meta41= { "DANGER", "RANGER", "MANGER", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
66
	private static final String[] meta42= { "E", "I", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
67
	private static final String[] meta43= { "RGY", "OGY", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
68
	private static final String[] meta44= { "E", "I", "Y", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
69
	private static final String[] meta45= { "AGGI", "OGGI", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
70
	private static final String[] meta46= { "VAN ", "VON ", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
71
	private static final String[] meta47= { "SCH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
72
	private static final String[] meta48= { "ET", "" }; //$NON-NLS-1$ //$NON-NLS-2$
73
	private static final String[] meta49= { "C", "X", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
74
	private static final String[] meta50= { "JOSE", "" }; //$NON-NLS-1$ //$NON-NLS-2$
75
	private static final String[] meta51= { "SAN ", "" }; //$NON-NLS-1$ //$NON-NLS-2$
76
	private static final String[] meta52= { "SAN ", "" }; //$NON-NLS-1$ //$NON-NLS-2$
77
	private static final String[] meta53= { "JOSE", "" }; //$NON-NLS-1$ //$NON-NLS-2$
78
	private static final String[] meta54= { "L", "T", "K", "S", "N", "M", "B", "Z", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$
79
	private static final String[] meta55= { "S", "K", "L", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
80
	private static final String[] meta56= { "ILLO", "ILLA", "ALLE", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
81
	private static final String[] meta57= { "AS", "OS", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
82
	private static final String[] meta58= { "A", "O", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
83
	private static final String[] meta59= { "ALLE", "" }; //$NON-NLS-1$ //$NON-NLS-2$
84
	private static final String[] meta60= { "UMB", "" }; //$NON-NLS-1$ //$NON-NLS-2$
85
	private static final String[] meta61= { "ER", "" }; //$NON-NLS-1$ //$NON-NLS-2$
86
	private static final String[] meta62= { "P", "B", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
87
	private static final String[] meta63= { "IE", "" }; //$NON-NLS-1$ //$NON-NLS-2$
88
	private static final String[] meta64= { "ME", "MA", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
89
	private static final String[] meta65= { "ISL", "YSL", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
90
	private static final String[] meta66= { "SUGAR", "" }; //$NON-NLS-1$ //$NON-NLS-2$
91
	private static final String[] meta67= { "SH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
92
	private static final String[] meta68= { "HEIM", "HOEK", "HOLM", "HOLZ", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
93
	private static final String[] meta69= { "SIO", "SIA", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
94
	private static final String[] meta70= { "SIAN", "" }; //$NON-NLS-1$ //$NON-NLS-2$
95
	private static final String[] meta71= { "M", "N", "L", "W", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
96
	private static final String[] meta72= { "Z", "" }; //$NON-NLS-1$ //$NON-NLS-2$
97
	private static final String[] meta73= { "Z", "" }; //$NON-NLS-1$ //$NON-NLS-2$
98
	private static final String[] meta74= { "SC", "" }; //$NON-NLS-1$ //$NON-NLS-2$
99
	private static final String[] meta75= { "OO", "ER", "EN", "UY", "ED", "EM", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
100
	private static final String[] meta76= { "ER", "EN", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
101
	private static final String[] meta77= { "I", "E", "Y", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
102
	private static final String[] meta78= { "AI", "OI", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
103
	private static final String[] meta79= { "S", "Z", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
104
	private static final String[] meta80= { "TION", "" }; //$NON-NLS-1$ //$NON-NLS-2$
105
	private static final String[] meta81= { "TIA", "TCH", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
106
	private static final String[] meta82= { "TH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
107
	private static final String[] meta83= { "TTH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
108
	private static final String[] meta84= { "OM", "AM", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
109
	private static final String[] meta85= { "VAN ", "VON ", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
110
	private static final String[] meta86= { "SCH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
111
	private static final String[] meta87= { "T", "D", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
112
	private static final String[] meta88= { "WR", "" }; //$NON-NLS-1$ //$NON-NLS-2$
113
	private static final String[] meta89= { "WH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
114
	private static final String[] meta90= { "EWSKI", "EWSKY", "OWSKI", "OWSKY", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
115
	private static final String[] meta91= { "SCH", "" }; //$NON-NLS-1$ //$NON-NLS-2$
116
	private static final String[] meta92= { "WICZ", "WITZ", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
117
	private static final String[] meta93= { "IAU", "EAU", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
118
	private static final String[] meta94= { "AU", "OU", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
119
	private static final String[] meta95= { "W", "K", "CZ", "WITZ" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
120
121
	/** The mutator characters */
122
	private static final char[] MUTATOR_CHARACTERS= { 'A', 'B', 'X', 'S', 'K', 'J', 'T', 'F', 'H', 'L', 'M', 'N', 'P', 'R', '0' };
123
124
	/** The vowel characters */
125
	private static final char[] VOWEL_CHARACTERS= new char[] { 'A', 'E', 'I', 'O', 'U', 'Y' };
126
127
	/**
128
	 * Test whether the specified string contains one of the candidates in the
129
	 * list.
130
	 *
131
	 * @param candidates
132
	 *                   Array of candidates to check
133
	 * @param token
134
	 *                   The token to check for occurrences of the candidates
135
	 * @param offset
136
	 *                   The offset where to begin checking in the string
137
	 * @param length
138
	 *                   The length of the range in the string to check
139
	 * @return <code>true</code> iff the string contains one of the
140
	 *               candidates, <code>false</code> otherwise.
141
	 */
142
	protected static final boolean hasOneOf(final String[] candidates, final char[] token, final int offset, final int length) {
143
144
		if (offset < 0 || offset >= token.length || candidates.length == 0)
145
			return false;
146
147
		final String checkable= new String(token, offset, length);
148
		for (int index= 0; index < candidates.length; index++) {
149
150
			if (candidates[index].equals(checkable))
151
				return true;
152
		}
153
		return false;
154
	}
155
156
	/**
157
	 * Test whether the specified token contains one of the candidates in the
158
	 * list.
159
	 *
160
	 * @param candidates
161
	 *                   Array of candidates to check
162
	 * @param token
163
	 *                   The token to check for occurrences of the candidates
164
	 * @return <code>true</code> iff the string contains one of the
165
	 *               candidates, <code>false</code> otherwise.
166
	 */
167
	protected static final boolean hasOneOf(final String[] candidates, final String token) {
168
169
		for (int index= 0; index < candidates.length; index++) {
170
171
			if (token.indexOf(candidates[index]) >= 0)
172
				return true;
173
		}
174
		return false;
175
	}
176
177
	/**
178
	 * Tests whether the specified token contains a vowel at the specified
179
	 * offset.
180
	 *
181
	 * @param token
182
	 *                   The token to check for a vowel
183
	 * @param offset
184
	 *                   The offset where to begin checking in the token
185
	 * @param length
186
	 *                   The length of the range in the token to check
187
	 * @return <code>true</code> iff the token contains a vowel, <code>false</code>
188
	 *               otherwise.
189
	 */
190
	protected static final boolean hasVowel(final char[] token, final int offset, final int length) {
191
192
		if (offset >= 0 && offset < length) {
193
194
			final char character= token[offset];
195
			for (int index= 0; index < VOWEL_CHARACTERS.length; index++) {
196
197
				if (VOWEL_CHARACTERS[index] == character)
198
					return true;
199
			}
200
		}
201
		return false;
202
	}
203
204
	/*
205
	 * @see org.eclipse.spelling.done.IPhoneticHasher#getHash(java.lang.String)
206
	 */
207
	public final String getHash(final String word) {
208
209
		final String input= word.toUpperCase() + "     "; //$NON-NLS-1$
210
		final char[] hashable= input.toCharArray();
211
212
		final boolean has95= hasOneOf(meta95, input);
213
		final StringBuffer buffer= new StringBuffer(hashable.length);
214
215
		int offset= 0;
216
		if (hasOneOf(meta26, hashable, 0, 2))
217
			offset += 1;
218
219
		if (hashable[0] == 'X') {
220
			buffer.append('S');
221
			offset += 1;
222
		}
223
224
		while (offset < hashable.length) {
225
226
			switch (hashable[offset]) {
227
				case 'A' :
228
				case 'E' :
229
				case 'I' :
230
				case 'O' :
231
				case 'U' :
232
				case 'Y' :
233
					if (offset == 0)
234
						buffer.append('A');
235
					offset += 1;
236
					break;
237
				case 'B' :
238
					buffer.append('P');
239
					if (hashable[offset + 1] == 'B')
240
						offset += 2;
241
					else
242
						offset += 1;
243
					break;
244
				case 'C' :
245
					if ((offset > 1) && !hasVowel(hashable, offset - 2, hashable.length) && hasOneOf(meta01, hashable, (offset - 1), 3) && (hashable[offset + 2] != 'I') && (hashable[offset + 2] != 'E') || hasOneOf(meta02, hashable, (offset - 2), 6)) {
246
						buffer.append('K');
247
						offset += 2;
248
						break;
249
					}
250
					if ((offset == 0) && hasOneOf(meta03, hashable, offset, 6)) {
251
						buffer.append('S');
252
						offset += 2;
253
						break;
254
					}
255
					if (hasOneOf(meta04, hashable, offset, 4)) {
256
						buffer.append('K');
257
						offset += 2;
258
						break;
259
					}
260
					if (hasOneOf(meta05, hashable, offset, 2)) {
261
						if ((offset > 0) && hasOneOf(meta06, hashable, offset, 4)) {
262
							buffer.append('K');
263
							offset += 2;
264
							break;
265
						}
266
						if ((offset == 0) && hasOneOf(meta07, hashable, (offset + 1), 5) || hasOneOf(meta08, hashable, offset + 1, 3) && !hasOneOf(meta09, hashable, 0, 5)) {
267
							buffer.append('K');
268
							offset += 2;
269
							break;
270
						}
271
						if (hasOneOf(meta10, hashable, 0, 4) || hasOneOf(meta11, hashable, 0, 3) || hasOneOf(meta12, hashable, offset - 2, 6) || hasOneOf(meta13, hashable, offset + 2, 1) || (hasOneOf(meta14, hashable, offset - 1, 1) || (offset == 0)) && hasOneOf(meta15, hashable, offset + 2, 1)) {
272
							buffer.append('K');
273
						} else {
274
							if (offset > 0) {
275
								if (hasOneOf(meta16, hashable, 0, 2))
276
									buffer.append('K');
277
								else
278
									buffer.append('X');
279
							} else {
280
								buffer.append('X');
281
							}
282
						}
283
						offset += 2;
284
						break;
285
					}
286
					if (hasOneOf(meta17, hashable, offset, 2) && !hasOneOf(meta18, hashable, offset, 4)) {
287
						buffer.append('S');
288
						offset += 2;
289
						break;
290
					}
291
					if (hasOneOf(meta19, hashable, offset, 2)) {
292
						buffer.append('X');
293
						offset += 2;
294
						break;
295
					}
296
					if (hasOneOf(meta20, hashable, offset, 2) && !((offset == 1) && hashable[0] == 'M')) {
297
						if (hasOneOf(meta21, hashable, offset + 2, 1) && !hasOneOf(meta22, hashable, offset + 2, 2)) {
298
							if (((offset == 1) && (hashable[offset - 1] == 'A')) || hasOneOf(meta23, hashable, (offset - 1), 5))
299
								buffer.append("KS"); //$NON-NLS-1$
300
							else
301
								buffer.append('X');
302
							offset += 3;
303
							break;
304
						} else {
305
							buffer.append('K');
306
							offset += 2;
307
							break;
308
						}
309
					}
310
					if (hasOneOf(meta24, hashable, offset, 2)) {
311
						buffer.append('K');
312
						offset += 2;
313
						break;
314
					} else if (hasOneOf(meta25, hashable, offset, 2)) {
315
						buffer.append('S');
316
						offset += 2;
317
						break;
318
					}
319
					buffer.append('K');
320
					if (hasOneOf(meta27, hashable, offset + 1, 2))
321
						offset += 3;
322
					else if (hasOneOf(meta28, hashable, offset + 1, 1) && !hasOneOf(meta29, hashable, offset + 1, 2))
323
						offset += 2;
324
					else
325
						offset += 1;
326
					break;
327
				case '\u00C7' :
328
					buffer.append('S');
329
					offset += 1;
330
					break;
331
				case 'D' :
332
					if (hasOneOf(meta30, hashable, offset, 2)) {
333
						if (hasOneOf(meta31, hashable, offset + 2, 1)) {
334
							buffer.append('J');
335
							offset += 3;
336
							break;
337
						} else {
338
							buffer.append("TK"); //$NON-NLS-1$
339
							offset += 2;
340
							break;
341
						}
342
					}
343
					buffer.append('T');
344
					if (hasOneOf(meta32, hashable, offset, 2)) {
345
						offset += 2;
346
					} else {
347
						offset += 1;
348
					}
349
					break;
350
				case 'F' :
351
					if (hashable[offset + 1] == 'F')
352
						offset += 2;
353
					else
354
						offset += 1;
355
					buffer.append('F');
356
					break;
357
				case 'G' :
358
					if (hashable[offset + 1] == 'H') {
359
						if ((offset > 0) && !hasVowel(hashable, offset - 1, hashable.length)) {
360
							buffer.append('K');
361
							offset += 2;
362
							break;
363
						}
364
						if (offset < 3) {
365
							if (offset == 0) {
366
								if (hashable[offset + 2] == 'I')
367
									buffer.append('J');
368
								else
369
									buffer.append('K');
370
								offset += 2;
371
								break;
372
							}
373
						}
374
						if ((offset > 1) && hasOneOf(meta33, hashable, offset - 2, 1) || ((offset > 2) && hasOneOf(meta34, hashable, offset - 3, 1)) || ((offset > 3) && hasOneOf(meta35, hashable, offset - 4, 1))) {
375
							offset += 2;
376
							break;
377
						} else {
378
							if ((offset > 2) && (hashable[offset - 1] == 'U') && hasOneOf(meta36, hashable, offset - 3, 1)) {
379
								buffer.append('F');
380
							} else {
381
								if ((offset > 0) && (hashable[offset - 1] != 'I'))
382
									buffer.append('K');
383
							}
384
							offset += 2;
385
							break;
386
						}
387
					}
388
					if (hashable[offset + 1] == 'N') {
389
						if ((offset == 1) && hasVowel(hashable, 0, hashable.length) && !has95) {
390
							buffer.append("KN"); //$NON-NLS-1$
391
						} else {
392
							if (!hasOneOf(meta37, hashable, offset + 2, 2) && (hashable[offset + 1] != 'Y') && !has95) {
393
								buffer.append("N"); //$NON-NLS-1$
394
							} else {
395
								buffer.append("KN"); //$NON-NLS-1$
396
							}
397
						}
398
						offset += 2;
399
						break;
400
					}
401
					if (hasOneOf(meta38, hashable, offset + 1, 2) && !has95) {
402
						buffer.append("KL"); //$NON-NLS-1$
403
						offset += 2;
404
						break;
405
					}
406
					if ((offset == 0) && ((hashable[offset + 1] == 'Y') || hasOneOf(meta39, hashable, offset + 1, 2))) {
407
						buffer.append('K');
408
						offset += 2;
409
						break;
410
					}
411
					if ((hasOneOf(meta40, hashable, offset + 1, 2) || (hashable[offset + 1] == 'Y')) && !hasOneOf(meta41, hashable, 0, 6) && !hasOneOf(meta42, hashable, offset - 1, 1) && !hasOneOf(meta43, hashable, offset - 1, 3)) {
412
						buffer.append('K');
413
						offset += 2;
414
						break;
415
					}
416
					if (hasOneOf(meta44, hashable, offset + 1, 1) || hasOneOf(meta45, hashable, offset - 1, 4)) {
417
						if (hasOneOf(meta46, hashable, 0, 4) || hasOneOf(meta47, hashable, 0, 3) || hasOneOf(meta48, hashable, offset + 1, 2)) {
418
							buffer.append('K');
419
						} else {
420
							buffer.append('J');
421
						}
422
						offset += 2;
423
						break;
424
					}
425
					if (hashable[offset + 1] == 'G')
426
						offset += 2;
427
					else
428
						offset += 1;
429
					buffer.append('K');
430
					break;
431
				case 'H' :
432
					if (((offset == 0) || hasVowel(hashable, offset - 1, hashable.length)) && hasVowel(hashable, offset + 1, hashable.length)) {
433
						buffer.append('H');
434
						offset += 2;
435
					} else {
436
						offset += 1;
437
					}
438
					break;
439
				case 'J' :
440
					if (hasOneOf(meta50, hashable, offset, 4) || hasOneOf(meta51, hashable, 0, 4)) {
441
						if ((offset == 0) && (hashable[offset + 4] == ' ') || hasOneOf(meta52, hashable, 0, 4)) {
442
							buffer.append('H');
443
						} else {
444
							buffer.append('J');
445
						}
446
						offset += 1;
447
						break;
448
					}
449
					if ((offset == 0) && !hasOneOf(meta53, hashable, offset, 4)) {
450
						buffer.append('J');
451
					} else {
452
						if (hasVowel(hashable, offset - 1, hashable.length) && !has95 && ((hashable[offset + 1] == 'A') || hashable[offset + 1] == 'O')) {
453
							buffer.append('J');
454
						} else {
455
							if (offset == (hashable.length - 1)) {
456
								buffer.append('J');
457
							} else {
458
								if (!hasOneOf(meta54, hashable, offset + 1, 1) && !hasOneOf(meta55, hashable, offset - 1, 1)) {
459
									buffer.append('J');
460
								}
461
							}
462
						}
463
					}
464
					if (hashable[offset + 1] == 'J')
465
						offset += 2;
466
					else
467
						offset += 1;
468
					break;
469
				case 'K' :
470
					if (hashable[offset + 1] == 'K')
471
						offset += 2;
472
					else
473
						offset += 1;
474
					buffer.append('K');
475
					break;
476
				case 'L' :
477
					if (hashable[offset + 1] == 'L') {
478
						if (((offset == (hashable.length - 3)) && hasOneOf(meta56, hashable, offset - 1, 4)) || ((hasOneOf(meta57, hashable, (hashable.length - 1) - 1, 2) || hasOneOf(meta58, hashable, hashable.length - 1, 1)) && hasOneOf(meta59, hashable, offset - 1, 4))) {
479
							buffer.append('L');
480
							offset += 2;
481
							break;
482
						}
483
						offset += 2;
484
					} else
485
						offset += 1;
486
					buffer.append('L');
487
					break;
488
				case 'M' :
489
					if ((hasOneOf(meta60, hashable, offset - 1, 3) && (((offset + 1) == (hashable.length - 1)) || hasOneOf(meta61, hashable, offset + 2, 2))) || (hashable[offset + 1] == 'M'))
490
						offset += 2;
491
					else
492
						offset += 1;
493
					buffer.append('M');
494
					break;
495
				case 'N' :
496
					if (hashable[offset + 1] == 'N')
497
						offset += 2;
498
					else
499
						offset += 1;
500
					buffer.append('N');
501
					break;
502
				case '\u00D1' :
503
					offset += 1;
504
					buffer.append('N');
505
					break;
506
				case 'P' :
507
					if (hashable[offset + 1] == 'N') {
508
						buffer.append('F');
509
						offset += 2;
510
						break;
511
					}
512
					if (hasOneOf(meta62, hashable, offset + 1, 1))
513
						offset += 2;
514
					else
515
						offset += 1;
516
					buffer.append('P');
517
					break;
518
				case 'Q' :
519
					if (hashable[offset + 1] == 'Q')
520
						offset += 2;
521
					else
522
						offset += 1;
523
					buffer.append('K');
524
					break;
525
				case 'R' :
526
					if (!((offset == (hashable.length - 1)) && !has95 && hasOneOf(meta63, hashable, offset - 2, 2) && !hasOneOf(meta64, hashable, offset - 4, 2)))
527
						buffer.append('R');
528
					if (hashable[offset + 1] == 'R')
529
						offset += 2;
530
					else
531
						offset += 1;
532
					break;
533
				case 'S' :
534
					if (hasOneOf(meta65, hashable, offset - 1, 3)) {
535
						offset += 1;
536
						break;
537
					}
538
					if ((offset == 0) && hasOneOf(meta66, hashable, offset, 5)) {
539
						buffer.append('X');
540
						offset += 1;
541
						break;
542
					}
543
					if (hasOneOf(meta67, hashable, offset, 2)) {
544
						if (hasOneOf(meta68, hashable, offset + 1, 4))
545
							buffer.append('S');
546
						else
547
							buffer.append('X');
548
						offset += 2;
549
						break;
550
					}
551
					if (hasOneOf(meta69, hashable, offset, 3) || hasOneOf(meta70, hashable, offset, 4)) {
552
						buffer.append('S');
553
						offset += 3;
554
						break;
555
					}
556
					if (((offset == 0) && hasOneOf(meta71, hashable, offset + 1, 1)) || hasOneOf(meta72, hashable, offset + 1, 1)) {
557
						buffer.append('S');
558
						if (hasOneOf(meta73, hashable, offset + 1, 1))
559
							offset += 2;
560
						else
561
							offset += 1;
562
						break;
563
					}
564
					if (hasOneOf(meta74, hashable, offset, 2)) {
565
						if (hashable[offset + 2] == 'H')
566
							if (hasOneOf(meta75, hashable, offset + 3, 2)) {
567
								if (hasOneOf(meta76, hashable, offset + 3, 2)) {
568
									buffer.append("X"); //$NON-NLS-1$
569
								} else {
570
									buffer.append("SK"); //$NON-NLS-1$
571
								}
572
								offset += 3;
573
								break;
574
							} else {
575
								buffer.append('X');
576
								offset += 3;
577
								break;
578
							}
579
						if (hasOneOf(meta77, hashable, offset + 2, 1)) {
580
							buffer.append('S');
581
							offset += 3;
582
							break;
583
						}
584
						buffer.append("SK"); //$NON-NLS-1$
585
						offset += 3;
586
						break;
587
					}
588
					if (!((offset == (hashable.length - 1)) && hasOneOf(meta78, hashable, offset - 2, 2)))
589
						buffer.append('S');
590
					if (hasOneOf(meta79, hashable, offset + 1, 1))
591
						offset += 2;
592
					else
593
						offset += 1;
594
					break;
595
				case 'T' :
596
					if (hasOneOf(meta80, hashable, offset, 4)) {
597
						buffer.append('X');
598
						offset += 3;
599
						break;
600
					}
601
					if (hasOneOf(meta81, hashable, offset, 3)) {
602
						buffer.append('X');
603
						offset += 3;
604
						break;
605
					}
606
					if (hasOneOf(meta82, hashable, offset, 2) || hasOneOf(meta83, hashable, offset, 3)) {
607
						if (hasOneOf(meta84, hashable, (offset + 2), 2) || hasOneOf(meta85, hashable, 0, 4) || hasOneOf(meta86, hashable, 0, 3)) {
608
							buffer.append('T');
609
						} else {
610
							buffer.append('0');
611
						}
612
						offset += 2;
613
						break;
614
					}
615
					if (hasOneOf(meta87, hashable, offset + 1, 1)) {
616
						offset += 2;
617
					} else
618
						offset += 1;
619
					buffer.append('T');
620
					break;
621
				case 'V' :
622
					if (hashable[offset + 1] == 'V')
623
						offset += 2;
624
					else
625
						offset += 1;
626
					buffer.append('F');
627
					break;
628
				case 'W' :
629
					if (hasOneOf(meta88, hashable, offset, 2)) {
630
						buffer.append('R');
631
						offset += 2;
632
						break;
633
					}
634
					if ((offset == 0) && (hasVowel(hashable, offset + 1, hashable.length) || hasOneOf(meta89, hashable, offset, 2))) {
635
						buffer.append('A');
636
					}
637
					if (((offset == (hashable.length - 1)) && hasVowel(hashable, offset - 1, hashable.length)) || hasOneOf(meta90, hashable, offset - 1, 5) || hasOneOf(meta91, hashable, 0, 3)) {
638
						buffer.append('F');
639
						offset += 1;
640
						break;
641
					}
642
					if (hasOneOf(meta92, hashable, offset, 4)) {
643
						buffer.append("TS"); //$NON-NLS-1$
644
						offset += 4;
645
						break;
646
					}
647
					offset += 1;
648
					break;
649
				case 'X' :
650
					if (!((offset == (hashable.length - 1)) && (hasOneOf(meta93, hashable, offset - 3, 3) || hasOneOf(meta94, hashable, offset - 2, 2))))
651
						buffer.append("KS"); //$NON-NLS-1$
652
					if (hasOneOf(meta49, hashable, offset + 1, 1))
653
						offset += 2;
654
					else
655
						offset += 1;
656
					break;
657
				case 'Z' :
658
					if (hashable[offset + 1] == 'H') {
659
						buffer.append('J');
660
						offset += 2;
661
						break;
662
					} else {
663
						buffer.append('S');
664
					}
665
					if (hashable[offset + 1] == 'Z')
666
						offset += 2;
667
					else
668
						offset += 1;
669
					break;
670
				default :
671
					offset += 1;
672
			}
673
		}
674
		return buffer.toString();
675
	}
676
677
	/*
678
	 * @see org.eclipse.spelling.done.IPhoneticHasher#getMutators()
679
	 */
680
	public final char[] getMutators() {
681
		return MUTATOR_CHARACTERS;
682
	}
683
}
(-)src/org/eclipse/ui/internal/texteditor/spelling/engine/DefaultSpellChecker.java (+349 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.internal.texteditor.spelling.engine;
12
13
import java.util.Collections;
14
import java.util.HashSet;
15
import java.util.Iterator;
16
import java.util.Locale;
17
import java.util.Set;
18
19
import org.eclipse.core.runtime.Assert;
20
21
import org.eclipse.jface.preference.IPreferenceStore;
22
23
import org.eclipse.ui.texteditor.spelling.PreferenceConstants;
24
import org.eclipse.ui.texteditor.spelling.engine.ISpellCheckIterator;
25
import org.eclipse.ui.texteditor.spelling.engine.ISpellChecker;
26
import org.eclipse.ui.texteditor.spelling.engine.ISpellDictionary;
27
import org.eclipse.ui.texteditor.spelling.engine.ISpellEventListener;
28
29
30
/**
31
 * Default spell checker for standard text.
32
 *
33
 * @since 3.0
34
 */
35
public class DefaultSpellChecker implements ISpellChecker {
36
37
	/** Array of URL prefixes */
38
	public static final String[] URL_PREFIXES= new String[] { "http://", "https://", "www.", "ftp://", "ftps://", "news://", "mailto://" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
39
40
	/**
41
	 * Does this word contain digits?
42
	 *
43
	 * @param word the word to check
44
	 * @return <code>true</code> iff this word contains digits, <code>false></code> otherwise
45
	 */
46
	protected static boolean isDigits(final String word) {
47
48
		for (int index= 0; index < word.length(); index++) {
49
50
			if (Character.isDigit(word.charAt(index)))
51
				return true;
52
		}
53
		return false;
54
	}
55
56
	/**
57
	 * Does this word contain mixed-case letters?
58
	 *
59
	 * @param word
60
	 *                   The word to check
61
	 * @param sentence
62
	 *                   <code>true</code> iff the specified word starts a new
63
	 *                   sentence, <code>false</code> otherwise
64
	 * @return <code>true</code> iff the contains mixed-case letters, <code>false</code>
65
	 *               otherwise
66
	 */
67
	protected static boolean isMixedCase(final String word, final boolean sentence) {
68
69
		final int length= word.length();
70
		boolean upper= Character.isUpperCase(word.charAt(0));
71
72
		if (sentence && upper && (length > 1))
73
			upper= Character.isUpperCase(word.charAt(1));
74
75
		if (upper) {
76
77
			for (int index= length - 1; index > 0; index--) {
78
				if (Character.isLowerCase(word.charAt(index)))
79
					return true;
80
			}
81
		} else {
82
83
			for (int index= length - 1; index > 0; index--) {
84
				if (Character.isUpperCase(word.charAt(index)))
85
					return true;
86
			}
87
		}
88
		return false;
89
	}
90
91
	/**
92
	 * Does this word contain upper-case letters only?
93
	 *
94
	 * @param word
95
	 *                   The word to check
96
	 * @return <code>true</code> iff this word only contains upper-case
97
	 *               letters, <code>false</code> otherwise
98
	 */
99
	protected static boolean isUpperCase(final String word) {
100
101
		for (int index= word.length() - 1; index >= 0; index--) {
102
103
			if (Character.isLowerCase(word.charAt(index)))
104
				return false;
105
		}
106
		return true;
107
	}
108
109
	/**
110
	 * Does this word look like an URL?
111
	 *
112
	 * @param word
113
	 *                   The word to check
114
	 * @return <code>true</code> iff this word looks like an URL, <code>false</code>
115
	 *               otherwise
116
	 */
117
	protected static boolean isUrl(final String word) {
118
119
		for (int index= 0; index < URL_PREFIXES.length; index++) {
120
121
			if (word.startsWith(URL_PREFIXES[index]))
122
				return true;
123
		}
124
		return false;
125
	}
126
127
	/**
128
	 * The dictionaries to use for spell checking. Synchronized to avoid
129
	 * concurrent modifications.
130
	 */
131
	private final Set fDictionaries= Collections.synchronizedSet(new HashSet());
132
133
	/**
134
	 * The words to be ignored. Synchronized to avoid concurrent modifications.
135
	 */
136
	private final Set fIgnored= Collections.synchronizedSet(new HashSet());
137
138
	/**
139
	 * The preference store. Assumes the <code>IPreferenceStore</code>
140
	 * implementation is thread safe.
141
	 */
142
	private final IPreferenceStore fPreferences;
143
144
	/**
145
	 * The locale of this checker.
146
	 * @since 3.3
147
	 */
148
	private Locale fLocale;
149
150
	/**
151
	 * Creates a new default spell checker.
152
	 *
153
	 * @param store the preference store for this spell checker
154
	 * @param locale the locale
155
	 */
156
	public DefaultSpellChecker(IPreferenceStore store, Locale locale) {
157
		Assert.isLegal(store != null);
158
		Assert.isLegal(locale != null);
159
160
		fPreferences= store;
161
		fLocale= locale;
162
	}
163
164
	/*
165
	 * @see org.eclipse.spelling.done.ISpellChecker#addDictionary(org.eclipse.spelling.done.ISpellDictionary)
166
	 */
167
	public final void addDictionary(final ISpellDictionary dictionary) {
168
		// synchronizing is necessary as this is a write access
169
		fDictionaries.add(dictionary);
170
	}
171
172
	/*
173
	 * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellChecker#acceptsWords()
174
	 */
175
	public boolean acceptsWords() {
176
		// synchronizing might not be needed here since acceptWords is
177
		// a read-only access and only called in the same thread as
178
		// the modifying methods add/checkWord (?)
179
		Set copy;
180
		synchronized (fDictionaries) {
181
			copy= new HashSet(fDictionaries);
182
		}
183
184
		ISpellDictionary dictionary= null;
185
		for (final Iterator iterator= copy.iterator(); iterator.hasNext();) {
186
187
			dictionary= (ISpellDictionary)iterator.next();
188
			if (dictionary.acceptsWords())
189
				return true;
190
		}
191
		return false;
192
	}
193
194
	/*
195
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker#addWord(java.lang.String)
196
	 */
197
	public void addWord(final String word) {
198
		// synchronizing is necessary as this is a write access
199
		Set copy;
200
		synchronized (fDictionaries) {
201
			copy= new HashSet(fDictionaries);
202
		}
203
204
		final String addable= word.toLowerCase();
205
		for (final Iterator iterator= copy.iterator(); iterator.hasNext();) {
206
			ISpellDictionary dictionary= (ISpellDictionary)iterator.next();
207
			if (dictionary.acceptsWords())
208
				dictionary.addWord(addable);
209
		}
210
211
	}
212
213
	/*
214
	 * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellChecker#checkWord(java.lang.String)
215
	 */
216
	public final void checkWord(final String word) {
217
		// synchronizing is necessary as this is a write access
218
		fIgnored.remove(word.toLowerCase());
219
	}
220
221
	/*
222
	 * @see org.eclipse.spelling.done.ISpellChecker#execute(org.eclipse.spelling.ISpellCheckTokenizer)
223
	 */
224
	public void execute(final ISpellEventListener listener, final ISpellCheckIterator iterator) {
225
226
		final boolean ignoreDigits= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_DIGITS);
227
		final boolean ignoreMixed= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_MIXED);
228
		final boolean ignoreSentence= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_SENTENCE);
229
		final boolean ignoreUpper= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_UPPER);
230
		final boolean ignoreURLS= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_URLS);
231
		final boolean ignoreNonLetters= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_NON_LETTERS);
232
		final boolean ignoreSingleLetters= fPreferences.getBoolean(PreferenceConstants.SPELLING_IGNORE_SINGLE_LETTERS);
233
		final int problemsThreshold= 100;//TODO: assigned to 100 for testing, remove later // PreferenceConstants.getPreferenceStore().getInt(PreferenceConstants.SPELLING_PROBLEMS_THRESHOLD);
234
235
		iterator.setIgnoreSingleLetters(ignoreSingleLetters);
236
237
		Iterator iter= fDictionaries.iterator();
238
		while (iter.hasNext())
239
			((ISpellDictionary)iter.next()).setStripNonLetters(ignoreNonLetters);
240
241
		String word= null;
242
		boolean starts= false;
243
		int problemCount= 0;
244
245
		while (problemCount <= problemsThreshold && iterator.hasNext()) {
246
247
			word= (String)iterator.next();
248
			if (word != null) {
249
250
				// synchronizing is necessary as this is called inside the reconciler
251
				if (!fIgnored.contains(word)) {
252
253
					starts= iterator.startsSentence();
254
					if (!isCorrect(word)) {
255
256
					    boolean isMixed=  isMixedCase(word, true);
257
					    boolean isUpper= isUpperCase(word);
258
					    boolean isDigits= isDigits(word);
259
					    boolean isURL= isUrl(word);
260
261
					    if ( !ignoreMixed && isMixed || !ignoreUpper && isUpper || !ignoreDigits && isDigits || !ignoreURLS && isURL || !(isMixed || isUpper || isDigits || isURL)) {
262
					        listener.handle(new SpellEvent(this, word, iterator.getBegin(), iterator.getEnd(), starts, false));
263
					        problemCount++;
264
					    }
265
266
					} else {
267
268
						//TODO: code commented for testing
269
						/*if (!ignoreSentence && starts && Character.isLowerCase(word.charAt(0))) {
270
							listener.handle(new SpellEvent(this, word, iterator.getBegin(), iterator.getEnd(), true, true));
271
							problemCount++;
272
						}*/
273
					}
274
				}
275
			}
276
		}
277
	}
278
279
	/*
280
	 * @see org.eclipse.spelling.done.ISpellChecker#getProposals(java.lang.String,boolean)
281
	 */
282
	public Set getProposals(final String word, final boolean sentence) {
283
284
		// synchronizing might not be needed here since getProposals is
285
		// a read-only access and only called in the same thread as
286
		// the modifing methods add/removeDictionary (?)
287
		Set copy;
288
		synchronized (fDictionaries) {
289
			copy= new HashSet(fDictionaries);
290
		}
291
292
		ISpellDictionary dictionary= null;
293
		final HashSet proposals= new HashSet();
294
295
		for (final Iterator iterator= copy.iterator(); iterator.hasNext();) {
296
297
			dictionary= (ISpellDictionary)iterator.next();
298
			proposals.addAll(dictionary.getProposals(word, sentence));
299
		}
300
		return proposals;
301
	}
302
303
	/*
304
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker#ignoreWord(java.lang.String)
305
	 */
306
	public final void ignoreWord(final String word) {
307
		// synchronizing is necessary as this is a write access
308
		fIgnored.add(word.toLowerCase());
309
	}
310
311
	/*
312
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker#isCorrect(java.lang.String)
313
	 */
314
	public final boolean isCorrect(final String word) {
315
		// synchronizing is necessary as this is called from execute
316
		Set copy;
317
		synchronized (fDictionaries) {
318
			copy= new HashSet(fDictionaries);
319
		}
320
321
		if (fIgnored.contains(word.toLowerCase()))
322
			return true;
323
324
		ISpellDictionary dictionary= null;
325
		for (final Iterator iterator= copy.iterator(); iterator.hasNext();) {
326
327
			dictionary= (ISpellDictionary)iterator.next();
328
			if (dictionary.isCorrect(word))
329
				return true;
330
		}
331
		return false;
332
	}
333
334
	/*
335
	 * @see org.eclipse.spelling.done.ISpellChecker#removeDictionary(org.eclipse.spelling.done.ISpellDictionary)
336
	 */
337
	public final void removeDictionary(final ISpellDictionary dictionary) {
338
		// synchronizing is necessary as this is a write access
339
		fDictionaries.remove(dictionary);
340
	}
341
342
	/*
343
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker#getLocale()
344
	 * @since 3.3
345
	 */
346
	public Locale getLocale() {
347
		return fLocale;
348
	}
349
}
(-)src/org/eclipse/ui/internal/texteditor/spelling/engine/IPhoneticDistanceAlgorithm.java (+31 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.internal.texteditor.spelling.engine;
13
14
/**
15
 * Interface of algorithms to compute the phonetic distance between two words.
16
 *
17
 * @since 3.0
18
 */
19
public interface IPhoneticDistanceAlgorithm {
20
21
	/**
22
	 * Returns the non-negative phonetic distance between two words
23
	 *
24
	 * @param from
25
	 *                  The first word
26
	 * @param to
27
	 *                  The second word
28
	 * @return The non-negative phonetic distance between the words.
29
	 */
30
	public int getDistance(String from, String to);
31
}
(-)src/org/eclipse/ui/internal/texteditor/spelling/engine/IPhoneticHashProvider.java (+36 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.internal.texteditor.spelling.engine;
13
14
/**
15
 * Interface of hashers to compute the phonetic hash for a word.
16
 *
17
 * @since 3.0
18
 */
19
public interface IPhoneticHashProvider {
20
21
	/**
22
	 * Returns the phonetic hash for the word.
23
	 *
24
	 * @param word
25
	 *                  The word to get the phonetic hash for
26
	 * @return The phonetic hash for the word
27
	 */
28
	public String getHash(String word);
29
30
	/**
31
	 * Returns an array of characters to compute possible mutations.
32
	 *
33
	 * @return Array of possible mutator characters
34
	 */
35
	public char[] getMutators();
36
}
(-)src/org/eclipse/ui/internal/texteditor/spelling/engine/LocaleSensitiveSpellDictionary.java (+69 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.internal.texteditor.spelling.engine;
12
13
import java.net.MalformedURLException;
14
import java.net.URL;
15
import java.util.Locale;
16
17
import org.eclipse.ui.texteditor.spelling.engine.AbstractSpellDictionary;
18
19
20
/**
21
 * Platform wide read-only locale sensitive dictionary for spell checking.
22
 *
23
 * @since 3.0
24
 */
25
public class LocaleSensitiveSpellDictionary extends AbstractSpellDictionary {
26
27
	/** The locale of this dictionary */
28
	private final Locale fLocale;
29
30
	/** The location of the dictionaries */
31
	private final URL fLocation;
32
33
	/**
34
	 * Creates a new locale sensitive spell dictionary.
35
	 *
36
	 * @param locale
37
	 *                   The locale for this dictionary
38
	 * @param location
39
	 *                   The location of the locale sensitive dictionaries
40
	 */
41
	public LocaleSensitiveSpellDictionary(final Locale locale, final URL location) {
42
		fLocation= location;
43
		fLocale= locale;
44
	}
45
46
	/**
47
	 * Returns the locale of this dictionary.
48
	 *
49
	 * @return The locale of this dictionary
50
	 */
51
	public final Locale getLocale() {
52
		return fLocale;
53
	}
54
55
	/*
56
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary#getURL()
57
	 */
58
	protected final URL getURL() throws MalformedURLException {
59
		return new URL(fLocation, fLocale.toString() + ".dictionary");  //$NON-NLS-1$
60
	}
61
62
	/*
63
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary#getInitialSize()
64
	 * @since 3.6
65
	 */
66
	protected int getInitialSize() {
67
		return 32 * 1024;
68
	}
69
}
(-)src/org/eclipse/ui/internal/texteditor/spelling/engine/PersistentSpellDictionary.java (+99 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *     Benjamin Muskalla <b.muskalla@gmx.net> - [spell checking][implementation] PersistentSpellDictionary closes wrong stream - https://bugs.eclipse.org/bugs/show_bug.cgi?id=236421
11
 *******************************************************************************/
12
package org.eclipse.ui.internal.texteditor.spelling.engine;
13
14
import java.io.FileOutputStream;
15
import java.io.IOException;
16
import java.net.URL;
17
import java.nio.ByteBuffer;
18
import java.nio.charset.Charset;
19
20
import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
21
22
import org.eclipse.ui.texteditor.spelling.engine.AbstractSpellDictionary;
23
24
25
/**
26
 * Persistent modifiable word-list based dictionary.
27
 *
28
 * @since 3.0
29
 */
30
public class PersistentSpellDictionary extends AbstractSpellDictionary {
31
32
	/** The word list location */
33
	private final URL fLocation;
34
35
	/**
36
	 * Creates a new persistent spell dictionary.
37
	 *
38
	 * @param url the URL of the word list for this dictionary
39
	 */
40
	public PersistentSpellDictionary(final URL url) {
41
		fLocation= url;
42
	}
43
44
	/*
45
	 * @see org.eclipse.jdt.ui.text.spelling.engine.AbstractSpellDictionary#acceptsWords()
46
	 */
47
	public boolean acceptsWords() {
48
		return true;
49
	}
50
51
	/*
52
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary#addWord(java.lang.String)
53
	 */
54
	public void addWord(final String word) {
55
		if (isCorrect(word))
56
			return;
57
58
		FileOutputStream fileStream= null;
59
		try {
60
			Charset charset= Charset.forName(getEncoding());
61
			ByteBuffer byteBuffer= charset.encode(word + "\n"); //$NON-NLS-1$
62
			int size= byteBuffer.limit();
63
			final byte[] byteArray;
64
			if (byteBuffer.hasArray())
65
				byteArray= byteBuffer.array();
66
			else {
67
				byteArray= new byte[size];
68
				byteBuffer.get(byteArray);
69
			}
70
71
			fileStream= new FileOutputStream(fLocation.getPath(), true);
72
73
			// Encoding UTF-16 charset writes a BOM. In which case we need to cut it away if the file isn't empty
74
			int bomCutSize= 0;
75
			if (!isEmpty() && "UTF-16".equals(charset.name())) //$NON-NLS-1$
76
				bomCutSize= 2;
77
78
			fileStream.write(byteArray, bomCutSize, size - bomCutSize);
79
		} catch (IOException exception) {
80
			TextEditorPlugin.log(exception);
81
			return;
82
		} finally {
83
			try {
84
				if (fileStream != null)
85
					fileStream.close();
86
			} catch (IOException e) {
87
			}
88
		}
89
90
		hashWord(word);
91
	}
92
93
	/*
94
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary#getURL()
95
	 */
96
	protected final URL getURL() {
97
		return fLocation;
98
	}
99
}
(-)src/org/eclipse/ui/internal/texteditor/spelling/engine/SpellEvent.java (+112 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2007 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.internal.texteditor.spelling.engine;
13
14
import java.util.Set;
15
16
import org.eclipse.ui.texteditor.spelling.engine.ISpellChecker;
17
import org.eclipse.ui.texteditor.spelling.engine.ISpellEvent;
18
19
/**
20
 * Spell event fired for words detected by a spell check iterator.
21
 *
22
 * @since 3.0
23
 */
24
public class SpellEvent implements ISpellEvent {
25
26
	/** The begin index of the word in the spell checkable medium */
27
	private final int fBegin;
28
29
	/** The spell checker that causes the event */
30
	private final ISpellChecker fChecker;
31
32
	/** The end index of the word in the spell checkable medium */
33
	private final int fEnd;
34
35
	/** Was the word found in the dictionary? */
36
	private final boolean fMatch;
37
38
	/** Does the word start a new sentence? */
39
	private final boolean fSentence;
40
41
	/** The word that causes the spell event */
42
	private final String fWord;
43
44
	/**
45
	 * Creates a new spell event.
46
	 *
47
	 * @param checker
48
	 *                   The spell checker that causes the event
49
	 * @param word
50
	 *                   The word that causes the event
51
	 * @param begin
52
	 *                   The begin index of the word in the spell checkable medium
53
	 * @param end
54
	 *                   The end index of the word in the spell checkable medium
55
	 * @param sentence
56
	 *                   <code>true</code> iff the word starts a new sentence,
57
	 *                   <code>false</code> otherwise
58
	 * @param match
59
	 *                   <code>true</code> iff the word was found in the dictionary,
60
	 *                   <code>false</code> otherwise
61
	 */
62
	protected SpellEvent(final ISpellChecker checker, final String word, final int begin, final int end, final boolean sentence, final boolean match) {
63
		fChecker= checker;
64
		fEnd= end;
65
		fBegin= begin;
66
		fWord= word;
67
		fSentence= sentence;
68
		fMatch= match;
69
	}
70
71
	/*
72
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEvent#getBegin()
73
	 */
74
	public final int getBegin() {
75
		return fBegin;
76
	}
77
78
	/*
79
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEvent#getEnd()
80
	 */
81
	public final int getEnd() {
82
		return fEnd;
83
	}
84
85
	/*
86
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEvent#getProposals()
87
	 */
88
	public final Set getProposals() {
89
		return fChecker.getProposals(fWord, fSentence);
90
	}
91
92
	/*
93
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEvent#getWord()
94
	 */
95
	public final String getWord() {
96
		return fWord;
97
	}
98
99
	/*
100
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEvent#isMatch()
101
	 */
102
	public final boolean isMatch() {
103
		return fMatch;
104
	}
105
106
	/*
107
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEvent#isStart()
108
	 */
109
	public final boolean isStart() {
110
		return fSentence;
111
	}
112
}
(-)src/org/eclipse/ui/internal/texteditor/spelling/engine/package.html (+84 lines)
Added Link Here
1
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
2
<html>
3
<head>
4
   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
5
   <meta name="Author" content="IBM">
6
   <meta name="GENERATOR" content="Mozilla/4.51 [en] (WinNT; I) [Netscape]">
7
   <title>Package-level Javadoc</title>
8
</head>
9
<body>
10
Provides the core functionality for spell-checking documents
11
<h2>
12
Package Specification</h2>
13
This package provides the interfaces for the notions of dictionary, edit distance, phonetic hash, 
14
spell event and spell-check iterator. For most of these interfaces a default implementation 
15
for english languages is provided. These implementations can be reused in custom dictionaries or 
16
spell-check iterators, or replaced by more specialized algorithms for a particular group of languages.
17
<h3>
18
Spell Check Engine</h3>
19
The central point to access the spell-checker functionality is the interface <tt>ISpellCheckEngine</tt>. 
20
Implementations of this interface provide support for life-cycle management, registering and unregistering
21
dictionaries, changing the locale of the engine and creating a spell-checker for a specific language.
22
<p>
23
The following steps are needed to obtain a spell-checker for a specific language:
24
<ul>
25
<li>Create an instance of <tt>ISpellCheckEngine</tt>. In this package, no default implementation is provided, 
26
since the management of the dictionary registering and loading is application dependent. Usually, instances 
27
of <tt>ISpellCheckEngine</tt> are implemented as singletons.</li>
28
<li>Create the appropriate dictionaries that should be used during the spell-check process. All dictionaries that 
29
can be registered with <tt>ISpellCheckEngine</tt> must implement the interface <tt>ISpellCheckDictionary</tt>. 
30
For this interface, an abstract implementation is provided in the class <tt>AbstractSpellDictionary</tt>.
31
Depending on the language of the words contained in this dictionary, custom algorithms for the phonetic hash
32
 (<tt>IPhoneticHashProvider</tt>) and the edit distance (<tt>IPhoneticDistanceAlgorithm</tt>) should be implemented 
33
 and registered with the dictionary.</li>
34
 <li>Instances of spell-checkers can now be created by calling <tt>createSpellChecker(Locale)</tt>, where the locale 
35
 denotes the language that the spell-checker should use while executing.</li>
36
</ul>
37
When requesting a new spell-checker with a different locale via <tt>createSpellChecker(Locale)</tt>, the spell-checker is 
38
reconfigured with the new dictionaries. More concretely, the old dictionary is unregistered and a new one registered for the 
39
desired locale is associated with the spell-checker. If no such dictionary is available, no spell-checker is returned and 
40
the locale of the engine is reset to its default locale.
41
<h3>
42
Dictionaries</h3>
43
Dictionaries are the data structures to hold word lists for a particular language. All implementations of dictionaries must 
44
implement the interface <tt>ISpellDictionary</tt>. It provides support for life-cycle management as well as the facility to query 
45
words from the list, add words to the list and get correction proposals for incorrectly spelt words.
46
<p>
47
This package provides a default implementation of a dictionary (<tt>AbstractSpellDictionary</tt>) that uses algorithms 
48
convenient for english languages. <br>
49
Every dictionary needs two kinds of algorithms to be plugged in:
50
<ul>
51
<li>An edit distance algorithm: Edit distance algorithms implement the interface <tt>IPhoneticDistanceAlgorithm</tt>. The algorithm 
52
is used to determine the similarity between two words. This package provides a default implementation for languages using the latin alphabet (<tt>DefaultPhoneticDistanceAlgorithm</tt>). 
53
The default algorithm uses the Levenshtein text edit distance.</li>
54
<li>A hash algorithm: Phonetic hash providers implement the interface <tt>IPhoneticHashProvider</tt>. The purpose of 
55
phonetic hashes is to have a representation of words which allows comparing it to other, similar words. This package provides a default 
56
implementation which is convenient for slavic and english languages. It uses the double metaphone algorithm by published 
57
Lawrence Philips.</li>
58
</ul>
59
By plugging in custom implementations of one or both of these algorithms the abstract implementation <tt>AbstractSpellDictionary</tt> can 
60
be customized to specified languages and alphabets.
61
<h3>
62
Spell Check Iterators</h3>
63
Instances of <tt>ISpellChecker</tt> are usually language-, locale- and medium independent implementations and therefore need an input provider. The 
64
interface <tt>ISpellCheckIterator</tt> serves this purpose by abstracting the tokenizing of text media to a simple iteration. The actual spell-check process 
65
is launched by calling <tt>ISpellChecker#execute(ISpellCheckIterator)</tt>. This method uses the indicated spell-check iterator to determine the 
66
words that are to be spell-checked. This package provides no default implementation of a spell-check iterator.
67
<h3>
68
Event Handling</h3>
69
To communicate the results of a spell-check pass, spell-checkers fire spell events that inform listeners about the status 
70
of a particular word being spell-checked. Instances that are interested in receiving spell events must implement 
71
the interface <tt>ISpellEventListener</tt> and register with the spell-checker before the spell-check process starts.<p>
72
A spell event contains the following information:
73
<ul>
74
<li>The word being spell-checked</li>
75
<li>The begin index of the current word in the text medium</li>
76
<li>The end index in the text medium</li>
77
<li>A flag whether this word was found in one of the registered dictionaries</li>
78
<li>A flag that indicates whether this word starts a new sentence</li>
79
<li>The set of proposals if the word was not correctly spelt. This information is lazily computed.</li>
80
</ul>
81
Spell event listeners are free to handle the events in any way. However, listeners are not allowed to block during 
82
the event handling unless the spell-checking process happens in another thread.
83
</body>
84
</html>
(-)src/org/eclipse/ui/texteditor/spelling/ISpellingEngine.java (-44 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.texteditor.spelling;
13
14
import org.eclipse.core.runtime.IProgressMonitor;
15
16
import org.eclipse.jface.text.IDocument;
17
import org.eclipse.jface.text.IRegion;
18
19
/**
20
 * A spelling engine that can be contributed to the
21
 * <code>org.eclipse.ui.workbench.texteditor.spellingEngine</code> extension
22
 * point. The <code>SpellingContext</code> provides information about the
23
 * content type to be checked. In general a spelling engine should at least
24
 * support the text {@link org.eclipse.core.runtime.content.IContentType content type}.
25
 * <p>
26
 * This interface is intended to be implemented by clients.
27
 * </p>
28
 *
29
 * @since 3.1
30
 */
31
public interface ISpellingEngine {
32
33
	/**
34
	 * Checks the given regions in the given document. Reports all found
35
	 * spelling problems to the collector.
36
	 *
37
	 * @param document the document to check
38
	 * @param regions the regions to check
39
	 * @param context the context
40
	 * @param collector the problem collector
41
	 * @param monitor the progress monitor, can be <code>null</code>
42
	 */
43
	public void check(IDocument document, IRegion[] regions, SpellingContext context, ISpellingProblemCollector collector, IProgressMonitor monitor);
44
}
(-)src/org/eclipse/ui/texteditor/spelling/PreferenceConstants.java (+431 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *     Guven Demir <guven.internet+eclipse@gmail.com> - [package explorer] Alternative package name shortening: abbreviation - https://bugs.eclipse.org/bugs/show_bug.cgi?id=299514
11
 *******************************************************************************/
12
package org.eclipse.ui.texteditor.spelling;
13
14
import java.util.Locale;
15
import java.util.StringTokenizer;
16
17
import org.eclipse.core.runtime.Assert;
18
import org.eclipse.core.runtime.preferences.DefaultScope;
19
import org.eclipse.core.runtime.preferences.InstanceScope;
20
21
import org.eclipse.core.resources.IProject;
22
import org.eclipse.core.resources.ProjectScope;
23
24
import org.eclipse.jface.preference.IPreferenceStore;
25
26
import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
27
28
import org.eclipse.ui.texteditor.spelling.engine.SpellCheckEngine;
29
30
31
/**
32
 * Preference constants used in the JDT-UI preference store. Clients should only read the
33
 * JDT-UI preference store using these values. Clients are not allowed to modify the
34
 * preference store programmatically.
35
 * <p>
36
 * This class it is not intended to be instantiated or subclassed by clients.
37
 * </p>
38
 *
39
 * @since 2.0
40
 *
41
 * @noinstantiate This class is not intended to be instantiated by clients.
42
 * @noextend This class is not intended to be subclassed by clients.
43
  */
44
public class PreferenceConstants {
45
46
	private PreferenceConstants() {
47
	}
48
49
	/**
50
	 * A named preference that controls which completion proposal categories have been excluded from
51
	 * the default proposal list.
52
	 * <p>
53
	 * Value is of type <code>String</code>, a "\0"-separated list of identifiers.
54
	 * </p>
55
	 * 
56
	 * @see #getExcludedCompletionProposalCategories()
57
	 * @see #setExcludedCompletionProposalCategories(String[])
58
	 * @since 3.2
59
	 */
60
	public static final String CODEASSIST_EXCLUDED_CATEGORIES= "content_assist_disabled_computers"; //$NON-NLS-1$
61
62
63
	/**
64
	 * A named preference that controls return type rendering of methods in the UI.
65
	 * <p>
66
	 * Value is of type <code>Boolean</code>: if <code>true</code> return types
67
	 * are rendered
68
	 * </p>
69
	 */
70
	public static final String APPEARANCE_METHOD_RETURNTYPE= "org.eclipse.jdt.ui.methodreturntype";//$NON-NLS-1$
71
72
	/**
73
	 * A named preference that controls type parameter rendering of methods in the UI.
74
	 * <p>
75
	 * Value is of type <code>Boolean</code>: if <code>true</code> return types
76
	 * are rendered
77
	 * </p>
78
	 * @since 3.1
79
	 */
80
	public static final String APPEARANCE_METHOD_TYPEPARAMETERS= "org.eclipse.jdt.ui.methodtypeparametesr";//$NON-NLS-1$
81
82
	/**
83
	 * A named preference that controls if override indicators are rendered in the UI.
84
	 * <p>
85
	 * Value is of type <code>Boolean</code>: if <code>true</code> override
86
	 * indicators are rendered
87
	 * </p>
88
	 * @deprecated Override Indicator is now controlled on the platform's decorator preference page
89
	 */
90
	public static final String APPEARANCE_OVERRIDE_INDICATOR= "org.eclipse.jdt.ui.overrideindicator";//$NON-NLS-1$
91
92
	/**
93
	 * A named preference that controls if quick assist light bulbs are shown.
94
	 * <p>
95
	 * Value is of type <code>Boolean</code>: if <code>true</code> light bulbs are shown
96
	 * for quick assists.
97
	 * </p>
98
	 *
99
	 * @since 3.0
100
	 */
101
	public static final String EDITOR_QUICKASSIST_LIGHTBULB="org.eclipse.jdt.quickassist.lightbulb"; //$NON-NLS-1$
102
103
104
105
	/**
106
	 * A named preference that holds a list of possible JRE libraries used by the New Java Project wizard. A library
107
	 * consists of a description and an arbitrary number of <code>IClasspathEntry</code>s, that will represent the
108
	 * JRE on the new project's class path.
109
	 * <p>
110
	 * Value is of type <code>String</code>: a semicolon separated list of encoded JRE libraries.
111
	 * <code>NEWPROJECT_JRELIBRARY_INDEX</code> defines the currently used library. Clients
112
	 * should use the method <code>encodeJRELibrary</code> to encode a JRE library into a string
113
	 * and the methods <code>decodeJRELibraryDescription(String)</code> and <code>
114
	 * decodeJRELibraryClasspathEntries(String)</code> to decode the description and the array
115
	 * of class path entries from an encoded string.
116
	 * </p>
117
	 *
118
	 * @see #NEWPROJECT_JRELIBRARY_INDEX
119
	 * @see #encodeJRELibrary(String, IClasspathEntry[])
120
	 * @see #decodeJRELibraryDescription(String)
121
	 * @see #decodeJRELibraryClasspathEntries(String)
122
	 */
123
	public static final String NEWPROJECT_JRELIBRARY_LIST= "org.eclipse.jdt.ui.wizards.jre.list"; //$NON-NLS-1$
124
125
	/**
126
	 * A named preferences that specifies the current active JRE library.
127
	 * <p>
128
	 * Value is of type <code>Integer</code>: an index into the list of possible JRE libraries.
129
	 * </p>
130
	 *
131
	 * @see #NEWPROJECT_JRELIBRARY_LIST
132
	 */
133
	public static final String NEWPROJECT_JRELIBRARY_INDEX= "org.eclipse.jdt.ui.wizards.jre.index"; //$NON-NLS-1$
134
135
	/**
136
	 * A named preference that controls whether Java comments should be
137
	 * spell checked.
138
	 * <p>
139
	 * Value is of type <code>Boolean</code>.
140
	 * </p>
141
	 *
142
	 * @deprecated since 3.1, use {@link org.eclipse.ui.texteditor.spelling.SpellingService#PREFERENCE_SPELLING_ENABLED}
143
	 *             and {@link org.eclipse.ui.texteditor.spelling.SpellingService#PREFERENCE_SPELLING_ENGINE}
144
	 * @since 3.0
145
	 */
146
	public final static String SPELLING_CHECK_SPELLING= "spelling_check_spelling"; //$NON-NLS-1$
147
148
	/**
149
	 * A named preference that controls whether words containing digits should
150
	 * be skipped during spell checking.
151
	 * <p>
152
	 * Value is of type <code>Boolean</code>.
153
	 * </p>
154
	 *
155
	 * @since 3.0
156
	 */
157
	public final static String SPELLING_IGNORE_DIGITS= "spelling_ignore_digits"; //$NON-NLS-1$
158
159
	/**
160
	 * A named preference that controls whether mixed case words should be
161
	 * skipped during spell checking.
162
	 * <p>
163
	 * Value is of type <code>Boolean</code>.
164
	 * </p>
165
	 *
166
	 * @since 3.0
167
	 */
168
	public final static String SPELLING_IGNORE_MIXED= "spelling_ignore_mixed"; //$NON-NLS-1$
169
170
	/**
171
	 * A named preference that controls whether sentence capitalization should
172
	 * be ignored during spell checking.
173
	 * <p>
174
	 * Value is of type <code>Boolean</code>.
175
	 * </p>
176
	 *
177
	 * @since 3.0
178
	 */
179
	public final static String SPELLING_IGNORE_SENTENCE= "spelling_ignore_sentence"; //$NON-NLS-1$
180
181
	/**
182
	 * A named preference that controls whether upper case words should be
183
	 * skipped during spell checking.
184
	 * <p>
185
	 * Value is of type <code>Boolean</code>.
186
	 * </p>
187
	 *
188
	 * @since 3.0
189
	 */
190
	public final static String SPELLING_IGNORE_UPPER= "spelling_ignore_upper"; //$NON-NLS-1$
191
192
	/**
193
	 * A named preference that controls whether URLs should be ignored during
194
	 * spell checking.
195
	 * <p>
196
	 * Value is of type <code>Boolean</code>.
197
	 * </p>
198
	 *
199
	 * @since 3.0
200
	 */
201
	public final static String SPELLING_IGNORE_URLS= "spelling_ignore_urls"; //$NON-NLS-1$
202
203
	/**
204
	 * A named preference that controls whether single letters
205
	 * should be ignored during spell checking.
206
	 * <p>
207
	 * Value is of type <code>Boolean</code>.
208
	 * </p>
209
	 *
210
	 * @since 3.3
211
	 */
212
	public final static String SPELLING_IGNORE_SINGLE_LETTERS= "spelling_ignore_single_letters"; //$NON-NLS-1$
213
214
	/**
215
	 * A named preference that controls whether '&' in
216
	 * Java properties files are ignored.
217
	 * <p>
218
	 * Value is of type <code>Boolean</code>.
219
	 * </p>
220
	 *
221
	 * @since 3.3
222
	 */
223
	public final static String SPELLING_IGNORE_AMPERSAND_IN_PROPERTIES= "spelling_ignore_ampersand_in_properties"; //$NON-NLS-1$
224
225
	/**
226
	 * A named preference that controls whether non-letters at word boundaries
227
	 * should be ignored during spell checking.
228
	 * <p>
229
	 * Value is of type <code>Boolean</code>.
230
	 * </p>
231
	 *
232
	 * @since 3.3
233
	 */
234
	public final static String SPELLING_IGNORE_NON_LETTERS= "spelling_ignore_non_letters"; //$NON-NLS-1$
235
236
	/**
237
	 * A named preference that controls whether Java strings
238
	 * should be ignored during spell checking.
239
	 * <p>
240
	 * Value is of type <code>Boolean</code>.
241
	 * </p>
242
	 *
243
	 * @since 3.4
244
	 */
245
	public static final String SPELLING_IGNORE_JAVA_STRINGS= "spelling_ignore_java_strings"; //$NON-NLS-1$;
246
247
	/**
248
	 * A named preference that controls the locale used for spell checking.
249
	 * <p>
250
	 * Value is of type <code>String</code>.
251
	 * </p>
252
	 *
253
	 * @since 3.0
254
	 */
255
	public final static String SPELLING_LOCALE= "spelling_locale"; //$NON-NLS-1$
256
257
	/**
258
	 * A named preference that controls the number of proposals offered during
259
	 * spell checking.
260
	 * <p>
261
	 * Value is of type <code>Integer</code>.
262
	 * </p>
263
	 *
264
	 * @since 3.0
265
	 */
266
	public final static String SPELLING_PROPOSAL_THRESHOLD= "spelling_proposal_threshold"; //$NON-NLS-1$
267
268
	/**
269
	 * A named preference that controls the maximum number of problems reported during spell checking.
270
	 * <p>
271
	 * Value is of type <code>Integer</code>.
272
	 * </p>
273
	 *
274
	 * @since 3.4
275
	 */
276
	public final static String SPELLING_PROBLEMS_THRESHOLD= "spelling_problems_threshold"; //$NON-NLS-1$
277
278
	/**
279
	 * A named preference that specifies the workspace user dictionary.
280
	 * <p>
281
	 * Value is of type <code>Integer</code>.
282
	 * </p>
283
	 *
284
	 * @since 3.0
285
	 */
286
	public final static String SPELLING_USER_DICTIONARY= "spelling_user_dictionary"; //$NON-NLS-1$
287
288
	/**
289
	 * A named preference that specifies encoding of the workspace user dictionary.
290
	 * <p>
291
	 * Value is of type <code>String</code>.
292
	 * </p>
293
	 *
294
	 * @since 3.3
295
	 */
296
	public final static String SPELLING_USER_DICTIONARY_ENCODING= "spelling_user_dictionary_encoding"; //$NON-NLS-1$
297
298
	/**
299
	 * A named preference that specifies whether spelling dictionaries are available to content assist.
300
	 *
301
	 * <strong>Note:</strong> This is currently not supported because the spelling engine
302
	 * cannot return word proposals but only correction proposals.
303
	 * <p>
304
	 * Value is of type <code>Boolean</code>.
305
	 * </p>
306
	 *
307
	 * @since 3.0
308
	 */
309
	public final static String SPELLING_ENABLE_CONTENTASSIST= "spelling_enable_contentassist"; //$NON-NLS-1$
310
311
	
312
313
314
	//---------- Properties File Editor ----------
315
316
	/**
317
	 * Initializes the given preference store with the default values.
318
	 *
319
	 * @param store the preference store to be initialized
320
	 *
321
	 * @since 2.1
322
	 */
323
	public static void initializeDefaultValues(IPreferenceStore store) {
324
325
		// spell checking
326
		store.setDefault(PreferenceConstants.SPELLING_LOCALE, "en_US"); //$NON-NLS-1$
327
		String isInitializedKey= "spelling_locale_initialized"; //$NON-NLS-1$
328
		if (!store.getBoolean(isInitializedKey)) {
329
			store.setValue(isInitializedKey, true);
330
			Locale locale= SpellCheckEngine.getDefaultLocale();
331
			locale= SpellCheckEngine.findClosestLocale(locale);
332
			if (locale != null)
333
				store.setValue(PreferenceConstants.SPELLING_LOCALE, locale.toString());
334
		}
335
		store.setDefault(PreferenceConstants.SPELLING_IGNORE_DIGITS, true);
336
		store.setDefault(PreferenceConstants.SPELLING_IGNORE_MIXED, true);
337
		store.setDefault(PreferenceConstants.SPELLING_IGNORE_SENTENCE, true);
338
		store.setDefault(PreferenceConstants.SPELLING_IGNORE_UPPER, true);
339
		store.setDefault(PreferenceConstants.SPELLING_IGNORE_URLS, true);
340
		store.setDefault(PreferenceConstants.SPELLING_IGNORE_SINGLE_LETTERS, true);
341
		store.setDefault(PreferenceConstants.SPELLING_IGNORE_AMPERSAND_IN_PROPERTIES, true);
342
		store.setDefault(PreferenceConstants.SPELLING_IGNORE_NON_LETTERS, true);
343
		store.setDefault(PreferenceConstants.SPELLING_IGNORE_JAVA_STRINGS, true);
344
		store.setDefault(PreferenceConstants.SPELLING_USER_DICTIONARY, ""); //$NON-NLS-1$
345
346
		// Note: For backwards compatibility we must use the property and not the workspace default
347
		store.setDefault(PreferenceConstants.SPELLING_USER_DICTIONARY_ENCODING, System.getProperty("file.encoding")); //$NON-NLS-1$
348
349
		store.setDefault(PreferenceConstants.SPELLING_PROPOSAL_THRESHOLD, 20);
350
		store.setDefault(PreferenceConstants.SPELLING_PROBLEMS_THRESHOLD, 100);
351
		/*
352
		 * XXX: This is currently disabled because the spelling engine
353
		 * cannot return word proposals but only correction proposals.
354
		 */
355
		store.setToDefault(PreferenceConstants.SPELLING_ENABLE_CONTENTASSIST);
356
	}
357
358
	/**
359
	 * Returns the JDT-UI preference store.
360
	 *
361
	 * @return the JDT-UI preference store
362
	 */
363
	public static IPreferenceStore getPreferenceStore() {
364
		return TextEditorPlugin.getDefault().getPreferenceStore();
365
	}
366
367
	/**
368
	 * Returns the completion proposal categories which
369
	 * are excluded from the default proposal list.
370
	 *
371
	 * @return an array with the IDs of the excluded categories
372
	 * @see #CODEASSIST_EXCLUDED_CATEGORIES
373
	 * @since 3.4
374
	 */
375
	public static String[] getExcludedCompletionProposalCategories() {
376
		String encodedPreference= getPreference(CODEASSIST_EXCLUDED_CATEGORIES, null);
377
		StringTokenizer tokenizer= new StringTokenizer(encodedPreference, "\0"); //$NON-NLS-1$
378
		String[] result= new String[tokenizer.countTokens()];
379
		for (int i= 0; i < result.length; i++)
380
			result[i]= tokenizer.nextToken();
381
		return result;
382
	}
383
384
	/**
385
	 * Sets the completion proposal categories which are excluded from the
386
	 * default proposal list and reloads the registry.
387
	 *
388
	 * @param categories the array with the IDs of the excluded categories
389
	 * @see #CODEASSIST_EXCLUDED_CATEGORIES
390
	 * @since 3.4
391
	 */
392
	public static void setExcludedCompletionProposalCategories(String[] categories) {
393
		Assert.isLegal(categories != null);
394
		StringBuffer buf= new StringBuffer(50 * categories.length);
395
		for (int i= 0; i < categories.length; i++) {
396
			buf.append(categories[i]);
397
			buf.append('\0');
398
		}
399
		getPreferenceStore().setValue(CODEASSIST_EXCLUDED_CATEGORIES, buf.toString());
400
		//TODO: what to do with this ?
401
		//CompletionProposalComputerRegistry.getDefault().reload();
402
	}
403
404
	/**
405
	 * Returns the value for the given key in the given context.
406
	 * @param key The preference key
407
	 * @param project The current context or <code>null</code> if no context is available and the
408
	 * workspace setting should be taken. Note that passing <code>null</code> should
409
	 * be avoided.
410
	 * @return Returns the current value for the string.
411
	 * @since 3.1
412
	 */
413
414
	//TODO: it was : public static String getPreference(String key, IJavaProject project) {
415
	// does it affect anything?
416
	public static String getPreference(String key, IProject project) {
417
		String val;
418
		if (project != null) {
419
			val= new ProjectScope(project.getProject()).getNode(TextEditorPlugin.PLUGIN_ID).get(key, null);
420
			if (val != null) {
421
				return val;
422
			}
423
		}
424
		val= new InstanceScope().getNode(TextEditorPlugin.PLUGIN_ID).get(key, null);
425
		if (val != null) {
426
			return val;
427
		}
428
		return new DefaultScope().getNode(TextEditorPlugin.PLUGIN_ID).get(key, null);
429
	}
430
}
431
(-)src/org/eclipse/ui/texteditor/spelling/SpellCheckIterator.java (+433 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.texteditor.spelling;
12
13
import java.util.LinkedList;
14
import java.util.Locale;
15
16
import com.ibm.icu.text.BreakIterator;
17
18
import org.eclipse.jface.text.IDocument;
19
import org.eclipse.jface.text.IRegion;
20
import org.eclipse.jface.text.TextUtilities;
21
22
import org.eclipse.ui.internal.texteditor.spelling.engine.DefaultSpellChecker;
23
24
import org.eclipse.ui.texteditor.spelling.correction.IHtmlTagConstants;
25
import org.eclipse.ui.texteditor.spelling.correction.IJavaDocTagConstants;
26
import org.eclipse.ui.texteditor.spelling.engine.ISpellCheckIterator;
27
28
29
/**
30
 * Iterator to spell check javadoc comment regions.
31
 *
32
 * @since 3.0
33
 */
34
/*
35
 * Ha! this does more than javadoc
36
 */
37
public class SpellCheckIterator implements ISpellCheckIterator {
38
39
	/**
40
	 * The token that denotes whitespace.
41
	 * 
42
	 * @since 3.6
43
	 */
44
	private static final int WHITE_SPACE_TOKEN= -1;
45
46
	/** The content of the region */
47
	protected final String fContent;
48
49
	/** The line delimiter */
50
	private final String fDelimiter;
51
52
	/** The last token */
53
	protected String fLastToken= null;
54
55
	/** The next break */
56
	protected int fNext= 1;
57
58
	/** The offset of the region */
59
	protected final int fOffset;
60
61
	/** The predecessor break */
62
	private int fPredecessor;
63
64
	/** The previous break */
65
	protected int fPrevious= 0;
66
67
	/** The sentence breaks */
68
	private final LinkedList fSentenceBreaks= new LinkedList();
69
70
	/** Does the current word start a sentence? */
71
	private boolean fStartsSentence= false;
72
73
	/** The successor break */
74
	protected int fSuccessor;
75
76
	/** The word iterator */
77
	private final BreakIterator fWordIterator;
78
79
	private boolean fIsIgnoringSingleLetters;
80
81
	/**
82
	 * Creates a new spell check iterator.
83
	 *
84
	 * @param document the document containing the specified partition
85
	 * @param region the region to spell check
86
	 * @param locale the locale to use for spell checking
87
	 */
88
	public SpellCheckIterator(IDocument document, IRegion region, Locale locale) {
89
		this(document, region, locale, BreakIterator.getWordInstance(locale));
90
	}
91
92
	/**
93
	 * Creates a new spell check iterator.
94
	 *
95
	 * @param document the document containing the specified partition
96
	 * @param region the region to spell check
97
	 * @param locale the locale to use for spell checking
98
	 * @param breakIterator the break-iterator
99
	 */
100
	public SpellCheckIterator(IDocument document, IRegion region, Locale locale, BreakIterator breakIterator) {
101
		fOffset= region.getOffset();
102
		fWordIterator= breakIterator;
103
		fDelimiter= TextUtilities.getDefaultLineDelimiter(document);
104
105
		String content;
106
		try {
107
108
			content= document.get(region.getOffset(), region.getLength());
109
			//TODO: Fix this
110
			//if (content.startsWith(NLSElement.TAG_PREFIX))
111
			if (content.startsWith("//$NON-NLS-")) //$NON-NLS-1$
112
				content= ""; //$NON-NLS-1$
113
114
		} catch (Exception exception) {
115
			content= ""; //$NON-NLS-1$
116
		}
117
		fContent= content;
118
119
		fWordIterator.setText(content);
120
		fPredecessor= fWordIterator.first();
121
		fSuccessor= fWordIterator.next();
122
123
		final BreakIterator iterator= BreakIterator.getSentenceInstance(locale);
124
		iterator.setText(content);
125
126
		int offset= iterator.current();
127
		while (offset != BreakIterator.DONE) {
128
129
			fSentenceBreaks.add(new Integer(offset));
130
			offset= iterator.next();
131
		}
132
	}
133
134
	/*
135
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckIterator#setIgnoreSingleLetters(boolean)
136
	 * @since 3.3
137
	 */
138
	public void setIgnoreSingleLetters(boolean state) {
139
		fIsIgnoringSingleLetters= state;
140
	}
141
142
	/*
143
	 * @see org.eclipse.spelling.done.ISpellCheckIterator#getBegin()
144
	 */
145
	public final int getBegin() {
146
		return fPrevious + fOffset;
147
	}
148
149
	/*
150
	 * @see org.eclipse.spelling.done.ISpellCheckIterator#getEnd()
151
	 */
152
	public final int getEnd() {
153
		return fNext + fOffset - 1;
154
	}
155
156
	/*
157
	 * @see java.util.Iterator#hasNext()
158
	 */
159
	public final boolean hasNext() {
160
		return fSuccessor != BreakIterator.DONE;
161
	}
162
163
	/**
164
	 * Does the specified token consist of at least one letter and digits
165
	 * only?
166
	 *
167
	 * @param begin the begin index
168
	 * @param end the end index
169
	 * @return <code>true</code> iff the token consists of digits and at
170
	 *         least one letter only, <code>false</code> otherwise
171
	 */
172
	protected final boolean isAlphaNumeric(final int begin, final int end) {
173
174
		char character= 0;
175
176
		boolean letter= false;
177
		for (int index= begin; index < end; index++) {
178
179
			character= fContent.charAt(index);
180
			if (Character.isLetter(character))
181
				letter= true;
182
183
			if (!Character.isLetterOrDigit(character))
184
				return false;
185
		}
186
		return letter;
187
	}
188
189
	/**
190
	 * Checks the last token against the given tags?
191
	 *
192
	 * @param tags the tags to check
193
	 * @return <code>true</code> iff the last token is in the given array
194
	 */
195
	protected final boolean isToken(final String[] tags) {
196
		return isToken(fLastToken, tags);
197
	}
198
199
	/**
200
	 * Checks the given  token against the given tags?
201
	 *
202
	 * @param token the token to check
203
	 * @param tags the tags to check
204
	 * @return <code>true</code> iff the last token is in the given array
205
	 * @since 3.3
206
	 */
207
	protected final boolean isToken(final String token, final String[] tags) {
208
209
		if (token != null) {
210
211
			for (int index= 0; index < tags.length; index++) {
212
213
				if (token.equals(tags[index]))
214
					return true;
215
			}
216
		}
217
		return false;
218
	}
219
220
	/**
221
	 * Is the current token a single letter token surrounded by
222
	 * non-whitespace characters?
223
	 *
224
	 * @param begin the begin index
225
	 * @return <code>true</code> iff the token is a single letter token,
226
	 *         <code>false</code> otherwise
227
	 */
228
	protected final boolean isSingleLetter(final int begin) {
229
		if (!Character.isLetter(fContent.charAt(begin)))
230
			return false;
231
232
		if (begin > 0 && !Character.isWhitespace(fContent.charAt(begin - 1)))
233
			return false;
234
235
		if (begin < fContent.length() - 1 && !Character.isWhitespace(fContent.charAt(begin + 1)))
236
			return false;
237
238
		return true;
239
	}
240
241
	/**
242
	 * Does the specified token look like an URL?
243
	 *
244
	 * @param begin the begin index
245
	 * @return <code>true</code> iff this token look like an URL,
246
	 *         <code>false</code> otherwise
247
	 */
248
	protected final boolean isUrlToken(final int begin) {
249
250
		for (int index= 0; index < DefaultSpellChecker.URL_PREFIXES.length; index++) {
251
252
			if (fContent.startsWith(DefaultSpellChecker.URL_PREFIXES[index], begin))
253
				return true;
254
		}
255
		return false;
256
	}
257
258
	/**
259
	 * Does the specified token consist of whitespace only?
260
	 *
261
	 * @param begin the begin index
262
	 * @param end the end index
263
	 * @return <code>true</code> iff the token consists of whitespace
264
	 *         only, <code>false</code> otherwise
265
	 */
266
	protected final boolean isWhitespace(final int begin, final int end) {
267
268
		for (int index= begin; index < end; index++) {
269
270
			if (!Character.isWhitespace(fContent.charAt(index)))
271
				return false;
272
		}
273
		return true;
274
	}
275
276
	/*
277
	 * @see java.util.Iterator#next()
278
	 */
279
	public Object next() {
280
281
		String token= nextToken();
282
		while (token == null && fSuccessor != BreakIterator.DONE)
283
			token= nextToken();
284
285
		fLastToken= token;
286
287
		return token;
288
	}
289
290
	/**
291
	 * Advances the end index to the next word break.
292
	 */
293
	protected final void nextBreak() {
294
295
		fNext= fSuccessor;
296
		fPredecessor= fSuccessor;
297
298
		fSuccessor= fWordIterator.next();
299
	}
300
301
	/**
302
	 * Returns the next sentence break.
303
	 *
304
	 * @return the next sentence break
305
	 */
306
	protected final int nextSentence() {
307
		return ((Integer) fSentenceBreaks.getFirst()).intValue();
308
	}
309
310
	/**
311
	 * Determines the next token to be spell checked.
312
	 *
313
	 * @return the next token to be spell checked, or <code>null</code>
314
	 *         iff the next token is not a candidate for spell checking.
315
	 */
316
	protected String nextToken() {
317
318
		String token= null;
319
320
		fPrevious= fPredecessor;
321
		fStartsSentence= false;
322
323
		nextBreak();
324
325
		boolean update= false;
326
		if (fNext - fPrevious > 0) {
327
328
			if (fSuccessor != BreakIterator.DONE && fContent.charAt(fPrevious) == IJavaDocTagConstants.JAVADOC_TAG_PREFIX) {
329
330
				nextBreak();
331
				if (Character.isLetter(fContent.charAt(fPrevious + 1))) {
332
					update= true;
333
					token= fContent.substring(fPrevious, fNext);
334
				} else
335
					fPredecessor= fNext;
336
337
			} else if (fSuccessor != BreakIterator.DONE && fContent.charAt(fPrevious) == IHtmlTagConstants.HTML_TAG_PREFIX && (Character.isLetter(fContent.charAt(fNext)) || fContent.charAt(fNext) == '/')) {
338
339
				if (fContent.startsWith(IHtmlTagConstants.HTML_CLOSE_PREFIX, fPrevious))
340
					nextBreak();
341
342
				nextBreak();
343
344
				if (fSuccessor != BreakIterator.DONE && fContent.charAt(fNext) == IHtmlTagConstants.HTML_TAG_POSTFIX) {
345
346
					nextBreak();
347
					if (fSuccessor != BreakIterator.DONE) {
348
						update= true;
349
						token= fContent.substring(fPrevious, fNext);
350
					}
351
				}
352
			} else if (fSuccessor != BreakIterator.DONE && fContent.charAt(fPrevious) == IHtmlTagConstants.HTML_ENTITY_START && (Character.isLetter(fContent.charAt(fNext)))) {
353
				nextBreak();
354
				if (fSuccessor != BreakIterator.DONE && fContent.charAt(fNext) == IHtmlTagConstants.HTML_ENTITY_END) {
355
					nextBreak();
356
					if (isToken(fContent.substring(fPrevious, fNext), IHtmlTagConstants.HTML_ENTITY_CODES)) {
357
						skipTokens(fPrevious, IHtmlTagConstants.HTML_ENTITY_END);
358
						update= true;
359
					} else
360
						token= fContent.substring(fPrevious, fNext);
361
				} else
362
					token= fContent.substring(fPrevious, fNext);
363
364
				update= true;
365
			} else if (!isWhitespace(fPrevious, fNext) && isAlphaNumeric(fPrevious, fNext)) {
366
367
				if (isUrlToken(fPrevious))
368
					skipTokens(fPrevious, WHITE_SPACE_TOKEN);
369
				else if (isToken(IJavaDocTagConstants.JAVADOC_PARAM_TAGS))
370
					fLastToken= null;
371
				else if (isToken(IJavaDocTagConstants.JAVADOC_REFERENCE_TAGS)) {
372
					fLastToken= null;
373
					skipTokens(fPrevious, fDelimiter.charAt(0));
374
				} else if (fNext - fPrevious > 1 || isSingleLetter(fPrevious) && !fIsIgnoringSingleLetters)
375
					token= fContent.substring(fPrevious, fNext);
376
377
				update= true;
378
			}
379
		}
380
381
		if (update && fSentenceBreaks.size() > 0) {
382
383
			if (fPrevious >= nextSentence()) {
384
385
				while (fSentenceBreaks.size() > 0 && fPrevious >= nextSentence())
386
					fSentenceBreaks.removeFirst();
387
388
				fStartsSentence= (fLastToken == null) || (token != null);
389
			}
390
		}
391
		return token;
392
	}
393
394
	/*
395
	 * @see java.util.Iterator#remove()
396
	 */
397
	public final void remove() {
398
		throw new UnsupportedOperationException();
399
	}
400
401
	/**
402
	 * Skip the tokens until the stop character is reached.
403
	 *
404
	 * @param begin the begin index
405
	 * @param stop the stop character
406
	 */
407
	protected final void skipTokens(final int begin, final int stop) {
408
		final boolean isStoppingOnWhiteSpace= stop == WHITE_SPACE_TOKEN;
409
		int end= begin;
410
		while (end < fContent.length()) {
411
			char ch= fContent.charAt(end);
412
			if (ch == stop || isStoppingOnWhiteSpace && Character.isWhitespace(ch))
413
				break;
414
			end++;
415
		}
416
417
		if (end < fContent.length()) {
418
419
			fNext= end;
420
			fPredecessor= fNext;
421
422
			fSuccessor= fWordIterator.following(fNext);
423
		} else
424
			fSuccessor= BreakIterator.DONE;
425
	}
426
427
	/*
428
	 * @see org.eclipse.spelling.done.ISpellCheckIterator#startsSentence()
429
	 */
430
	public final boolean startsSentence() {
431
		return fStartsSentence;
432
	}
433
}
(-)src/org/eclipse/ui/texteditor/spelling/SpellingContext.java (+2 lines)
Lines 12-17 Link Here
12
12
13
import org.eclipse.core.runtime.content.IContentType;
13
import org.eclipse.core.runtime.content.IContentType;
14
14
15
import org.eclipse.ui.texteditor.spelling.engine.ISpellingEngine;
16
15
17
16
/**
18
/**
17
 * A spelling context allows a {@link ISpellingEngine} to retrieve information
19
 * A spelling context allows a {@link ISpellingEngine} to retrieve information
(-)src/org/eclipse/ui/texteditor/spelling/SpellingCorrectionProcessor.java (-119 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006, 2009 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.texteditor.spelling;
12
13
import java.util.ArrayList;
14
import java.util.Arrays;
15
import java.util.Iterator;
16
import java.util.List;
17
18
import org.eclipse.jface.text.Position;
19
import org.eclipse.jface.text.contentassist.ICompletionProposal;
20
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
21
import org.eclipse.jface.text.quickassist.IQuickAssistProcessor;
22
import org.eclipse.jface.text.source.Annotation;
23
import org.eclipse.jface.text.source.IAnnotationModel;
24
import org.eclipse.jface.text.source.ISourceViewer;
25
import org.eclipse.jface.text.source.TextInvocationContext;
26
27
import org.eclipse.ui.internal.texteditor.spelling.NoCompletionsProposal;
28
29
30
/**
31
 * Spelling correction processor used to show quick
32
 * fixes for spelling problems.
33
 *
34
 * @since 3.3
35
 */
36
public final class SpellingCorrectionProcessor implements IQuickAssistProcessor {
37
38
39
	private static final ICompletionProposal[] fgNoSuggestionsProposal=  new ICompletionProposal[] { new NoCompletionsProposal() };
40
41
42
	/*
43
	 * @see IContentAssistProcessor#computeCompletionProposals(ITextViewer, int)
44
	 */
45
	public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationContext quickAssistContext) {
46
		ISourceViewer viewer= quickAssistContext.getSourceViewer();
47
		int documentOffset= quickAssistContext.getOffset();
48
49
		int length= viewer != null ? viewer.getSelectedRange().y : -1;
50
		TextInvocationContext context= new TextInvocationContext(viewer, documentOffset, length);
51
52
53
		IAnnotationModel model= viewer.getAnnotationModel();
54
		if (model == null)
55
			return fgNoSuggestionsProposal;
56
57
		List proposals= computeProposals(context, model);
58
		if (proposals.isEmpty())
59
			return fgNoSuggestionsProposal;
60
61
		return (ICompletionProposal[]) proposals.toArray(new ICompletionProposal[proposals.size()]);
62
	}
63
64
	private boolean isAtPosition(int offset, Position pos) {
65
		return (pos != null) && (offset >= pos.getOffset() && offset <= (pos.getOffset() +  pos.getLength()));
66
	}
67
68
	private List computeProposals(IQuickAssistInvocationContext context, IAnnotationModel model) {
69
		int offset= context.getOffset();
70
		ArrayList annotationList= new ArrayList();
71
		Iterator iter= model.getAnnotationIterator();
72
		while (iter.hasNext()) {
73
			Annotation annotation= (Annotation)iter.next();
74
			if (canFix(annotation)) {
75
				Position pos= model.getPosition(annotation);
76
				if (isAtPosition(offset, pos)) {
77
					collectSpellingProblems(annotation, annotationList);
78
				}
79
			}
80
		}
81
		SpellingProblem[] spellingProblems= (SpellingProblem[]) annotationList.toArray(new SpellingProblem[annotationList.size()]);
82
		return computeProposals(context, spellingProblems);
83
	}
84
85
	private void collectSpellingProblems(Annotation annotation, List problems) {
86
		if (annotation instanceof SpellingAnnotation)
87
			problems.add(((SpellingAnnotation)annotation).getSpellingProblem());
88
	}
89
90
	private List computeProposals(IQuickAssistInvocationContext context, SpellingProblem[] spellingProblems) {
91
		List proposals= new ArrayList();
92
		for (int i= 0; i < spellingProblems.length; i++)
93
			proposals.addAll(Arrays.asList(spellingProblems[i].getProposals(context)));
94
95
		return proposals;
96
	}
97
98
	/*
99
	 * @see IContentAssistProcessor#getErrorMessage()
100
	 */
101
	public String getErrorMessage() {
102
		return null;
103
	}
104
105
	/*
106
	 * @see org.eclipse.jface.text.quickassist.IQuickAssistProcessor#canFix(org.eclipse.jface.text.source.Annotation)
107
	 */
108
	public boolean canFix(Annotation annotation) {
109
		return annotation instanceof SpellingAnnotation && !annotation.isMarkedDeleted();
110
	}
111
112
	/*
113
	 * @see org.eclipse.jface.text.quickassist.IQuickAssistProcessor#canAssist(org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext)
114
	 */
115
	public boolean canAssist(IQuickAssistInvocationContext invocationContext) {
116
		return false;
117
	}
118
119
}
(-)src/org/eclipse/ui/texteditor/spelling/SpellingEngineDescriptor.java (-3 / +23 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2008 IBM Corporation and others.
2
 * Copyright (c) 2005, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 19-24 Link Here
19
19
20
import org.eclipse.ui.internal.texteditor.spelling.EmptySpellingPreferenceBlock;
20
import org.eclipse.ui.internal.texteditor.spelling.EmptySpellingPreferenceBlock;
21
21
22
import org.eclipse.ui.texteditor.spelling.engine.ISpellingEngine;
23
22
/**
24
/**
23
 * Describes an extension to the <code>spellingEngine</code> extension point.
25
 * Describes an extension to the <code>spellingEngine</code> extension point.
24
 * <p>
26
 * <p>
Lines 36-41 Link Here
36
	private static final String CLASS_ATTRIBUTE= "class"; //$NON-NLS-1$
38
	private static final String CLASS_ATTRIBUTE= "class"; //$NON-NLS-1$
37
	/** Name of the <code>id</code> attribute. */
39
	/** Name of the <code>id</code> attribute. */
38
	private static final String ID_ATTRIBUTE= "id"; //$NON-NLS-1$
40
	private static final String ID_ATTRIBUTE= "id"; //$NON-NLS-1$
41
	/** Name of the <code>contentType</code> attribute. @since 3.7 */
42
	private static final String CONTENT_TYPE_ATTRIBUTE= "contentType"; //$NON-NLS-1$
39
	/** Name of the <code>default</code> attribute. */
43
	/** Name of the <code>default</code> attribute. */
40
	private static final String DEFAULT_ATTRIBUTE= "default"; //$NON-NLS-1$
44
	private static final String DEFAULT_ATTRIBUTE= "default"; //$NON-NLS-1$
41
	/** Name of the <code>preferencesClass</code> attribute. */
45
	/** Name of the <code>preferencesClass</code> attribute. */
Lines 47-52 Link Here
47
	private String fLabel;
51
	private String fLabel;
48
	/** The value of the <code>id</code> attribute, if read. */
52
	/** The value of the <code>id</code> attribute, if read. */
49
	private String fId;
53
	private String fId;
54
	/** The value of the <code>contentType</code> attribute, if read. */
55
	private String fContentType;
50
	/** The value of the <code>default</code> attribute, if read. */
56
	/** The value of the <code>default</code> attribute, if read. */
51
	private Boolean fDefault;
57
	private Boolean fDefault;
52
	/** The bundle where this extension was defined. */
58
	/** The bundle where this extension was defined. */
Lines 54-59 Link Here
54
	/** <code>true</code> iff a preferences class has been specified */
60
	/** <code>true</code> iff a preferences class has been specified */
55
	private Boolean fHasPreferences;
61
	private Boolean fHasPreferences;
56
62
63
57
	/**
64
	/**
58
	 * Creates a new descriptor for <code>element</code>.
65
	 * Creates a new descriptor for <code>element</code>.
59
	 * <p>
66
	 * <p>
Lines 75-81 Link Here
75
	public String getLabel() {
82
	public String getLabel() {
76
		if (fLabel == null) {
83
		if (fLabel == null) {
77
			fLabel= fConfiguration.getAttribute(LABEL_ATTRIBUTE);
84
			fLabel= fConfiguration.getAttribute(LABEL_ATTRIBUTE);
78
			Assert.isNotNull(fLabel);
85
			Assert.isNotNull(fLabel); //TODO:does not look right - this is optional
79
		}
86
		}
80
		return fLabel;
87
		return fLabel;
81
	}
88
	}
Lines 94-101 Link Here
94
	}
101
	}
95
102
96
	/**
103
	/**
104
	 * Reads (if needed) and returns the content type of this extension.
105
	 * 
106
	 * @return the content type for this extension.
107
	 * @since 3.7
108
	 */
109
	public String getContentType() {
110
		if (fContentType == null) {
111
			fContentType= fConfiguration.getAttribute(CONTENT_TYPE_ATTRIBUTE);
112
		}
113
		return fContentType;
114
	}
115
116
	/**
97
	 * Creates a spelling engine as described in the extension's xml.
117
	 * Creates a spelling engine as described in the extension's xml.
98
	 *
118
	 * 
99
	 * @return the created spelling engine
119
	 * @return the created spelling engine
100
	 * @throws CoreException if the creation failed
120
	 * @throws CoreException if the creation failed
101
	 */
121
	 */
(-)src/org/eclipse/ui/texteditor/spelling/SpellingService.java (-16 / +85 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 11-20 Link Here
11
11
12
package org.eclipse.ui.texteditor.spelling;
12
package org.eclipse.ui.texteditor.spelling;
13
13
14
import java.util.HashMap;
15
import java.util.Map;
16
14
import org.eclipse.core.runtime.CoreException;
17
import org.eclipse.core.runtime.CoreException;
15
import org.eclipse.core.runtime.IProgressMonitor;
18
import org.eclipse.core.runtime.IProgressMonitor;
16
import org.eclipse.core.runtime.ISafeRunnable;
19
import org.eclipse.core.runtime.ISafeRunnable;
17
import org.eclipse.core.runtime.SafeRunner;
20
import org.eclipse.core.runtime.SafeRunner;
21
import org.eclipse.core.runtime.content.IContentType;
18
22
19
import org.eclipse.jface.preference.IPreferenceStore;
23
import org.eclipse.jface.preference.IPreferenceStore;
20
24
Lines 25-30 Link Here
25
import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
29
import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
26
import org.eclipse.ui.internal.texteditor.spelling.SpellingEngineRegistry;
30
import org.eclipse.ui.internal.texteditor.spelling.SpellingEngineRegistry;
27
31
32
import org.eclipse.ui.texteditor.spelling.engine.ISpellingEngine;
33
28
/**
34
/**
29
 * System wide spelling service.
35
 * System wide spelling service.
30
 * <p>
36
 * <p>
Lines 36-41 Link Here
36
 */
42
 */
37
public class SpellingService {
43
public class SpellingService {
38
44
45
	/** Available spelling engines by content type */
46
	private Map fEngines= new HashMap();
47
39
	/**
48
	/**
40
	 * A named preference that controls if spelling is enabled or disabled.
49
	 * A named preference that controls if spelling is enabled or disabled.
41
	 * <p>
50
	 * <p>
Lines 97-103 Link Here
97
			collector.beginCollecting();
106
			collector.beginCollecting();
98
			if (fPreferences.getBoolean(PREFERENCE_SPELLING_ENABLED))
107
			if (fPreferences.getBoolean(PREFERENCE_SPELLING_ENABLED))
99
				try {
108
				try {
100
					final ISpellingEngine engine= createEngine(fPreferences);
109
					final ISpellingEngine engine= getEngine(context.getContentType(), fPreferences);
101
					if (engine != null) {
110
					if (engine != null) {
102
						ISafeRunnable runnable= new ISafeRunnable() {
111
						ISafeRunnable runnable= new ISafeRunnable() {
103
							public void run() throws Exception {
112
							public void run() throws Exception {
Lines 144-158 Link Here
144
	}
153
	}
145
154
146
	/**
155
	/**
147
	 * Returns the descriptor of the active spelling engine based on the
156
	 * Returns the descriptor of the active spelling engine based on the value of the
148
	 * value of the <code>PREFERENCE_SPELLING_ENGINE</code> preference
157
	 * <code>PREFERENCE_SPELLING_ENGINE</code> preference in the given preferences.
149
	 * in the given preferences.
158
	 * 
150
	 *
159
	 * @param contentType
160
	 * 
151
	 * @param preferences the preferences
161
	 * @param preferences the preferences
152
	 * @return the descriptor of the active spelling engine or
162
	 * @return the descriptor of the active spelling engine or <code>null</code> if none could be
153
	 *         <code>null</code> if none could be found
163
	 *         found
154
	 * @see SpellingService#PREFERENCE_SPELLING_ENGINE
164
	 * @see SpellingService#PREFERENCE_SPELLING_ENGINE
155
	 */
165
	 */
166
	public SpellingEngineDescriptor getActiveSpellingEngineDescriptor(IContentType contentType, IPreferenceStore preferences) {
167
		SpellingEngineRegistry registry= getSpellingEngineRegistry();
168
		if (registry == null)
169
			return null;
170
171
		SpellingEngineDescriptor descriptor= registry.getDescriptor(contentType);
172
		if (descriptor == null) {
173
			descriptor= registry.getDefaultDescriptor();
174
		}
175
		return descriptor;
176
	}
177
178
	/**
179
	 * Returns the descriptor of the active spelling engine based on the value of the
180
	 * <code>PREFERENCE_SPELLING_ENGINE</code> preference in the given preferences.
181
	 * 
182
	 * @param contentType
183
	 * 
184
	 * @param preferences the preferences
185
	 * @return the descriptor of the active spelling engine or <code>null</code> if none could be
186
	 *         found
187
	 * @see SpellingService#PREFERENCE_SPELLING_ENGINE
188
	 * @deprecated
189
	 * 
190
	 *             TODO: what to do with the concept of active spelling engine? now that the engine
191
	 *             is content type based? have multiple engines for a content type and one of them
192
	 *             active? overkill i would say
193
	 */
156
	public SpellingEngineDescriptor getActiveSpellingEngineDescriptor(IPreferenceStore preferences) {
194
	public SpellingEngineDescriptor getActiveSpellingEngineDescriptor(IPreferenceStore preferences) {
157
		SpellingEngineRegistry registry= getSpellingEngineRegistry();
195
		SpellingEngineRegistry registry= getSpellingEngineRegistry();
158
		if (registry == null)
196
		if (registry == null)
Lines 167-190 Link Here
167
	}
205
	}
168
206
169
	/**
207
	/**
170
	 * Creates a spelling engine based on the value of the
208
	 * Creates a spelling engine based on the value of the <code>PREFERENCE_SPELLING_ENGINE</code>
171
	 * <code>PREFERENCE_SPELLING_ENGINE</code> preference in the given
209
	 * preference in the given preferences.
172
	 * preferences.
210
	 * 
173
	 *
211
	 * @param contentType
212
	 * 
174
	 * @param preferences the preferences
213
	 * @param preferences the preferences
175
	 * @return the created spelling engine or <code>null</code> if none
214
	 * @return the created spelling engine or <code>null</code> if none could be created
176
	 *         could be created
177
	 * @throws CoreException if the creation failed
215
	 * @throws CoreException if the creation failed
178
	 * @see SpellingService#PREFERENCE_SPELLING_ENGINE
216
	 * @see SpellingService#PREFERENCE_SPELLING_ENGINE
179
	 */
217
	 */
180
	private ISpellingEngine createEngine(IPreferenceStore preferences) throws CoreException {
218
	private ISpellingEngine createEngine(IContentType contentType, IPreferenceStore preferences) throws CoreException {
181
		SpellingEngineDescriptor descriptor= getActiveSpellingEngineDescriptor(preferences);
219
		SpellingEngineDescriptor descriptor= getActiveSpellingEngineDescriptor(contentType, preferences);
182
		if (descriptor != null)
220
		if (descriptor != null)
183
			return descriptor.createEngine();
221
			return descriptor.createEngine();
184
		return null;
222
		return null;
185
	}
223
	}
186
224
187
	/**
225
	/**
226
	 * Returns a spelling engine for the given content type or <code>null</code> if none could be
227
	 * found.
228
	 * 
229
	 * @param contentType the content type
230
	 * @param preferences
231
	 * @return a spelling engine for the given content type or <code>null</code> if none could be
232
	 *         found
233
	 * @throws CoreException
234
	 */
235
	private ISpellingEngine getEngine(IContentType contentType, IPreferenceStore preferences) throws CoreException {
236
		if (contentType == null)
237
			return null;
238
239
		//'all content type' case is handled in SpellingEngineRegistry#getDescriptor(IContentType)
240
241
		if (fEngines.containsKey(contentType))
242
			return (ISpellingEngine)fEngines.get(contentType);
243
244
		//try to create engine
245
		ISpellingEngine engine= createEngine(contentType, preferences);
246
		if (engine != null) {
247
			fEngines.put(contentType, engine);
248
			return engine;
249
		}
250
251
		return getEngine(contentType.getBaseType(), preferences); // TODO: base type??
252
	}
253
254
255
256
	/**
188
	 * Returns the spelling engine registry.
257
	 * Returns the spelling engine registry.
189
	 *
258
	 *
190
	 * @return the spelling engine registry or <code>null</code> if the plug-in has been shutdown
259
	 * @return the spelling engine registry or <code>null</code> if the plug-in has been shutdown
(-)src/org/eclipse/ui/texteditor/spelling/TextSpellingProblem.java (+244 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.texteditor.spelling;
12
13
import java.util.ArrayList;
14
import java.util.Collections;
15
import java.util.List;
16
17
import org.eclipse.core.runtime.Assert;
18
19
import org.eclipse.jface.text.BadLocationException;
20
import org.eclipse.jface.text.IDocument;
21
import org.eclipse.jface.text.IRegion;
22
import org.eclipse.jface.text.contentassist.ICompletionProposal;
23
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
24
import org.eclipse.jface.text.source.TextInvocationContext;
25
26
import org.eclipse.ui.internal.texteditor.spelling.Messages;
27
import org.eclipse.ui.internal.texteditor.spelling.SpellingMessages;
28
29
import org.eclipse.ui.texteditor.spelling.correction.AddWordProposal;
30
import org.eclipse.ui.texteditor.spelling.correction.ChangeCaseProposal;
31
import org.eclipse.ui.texteditor.spelling.correction.DisableSpellCheckingProposal;
32
import org.eclipse.ui.texteditor.spelling.correction.IHtmlTagConstants;
33
import org.eclipse.ui.texteditor.spelling.correction.IJavaDocTagConstants;
34
import org.eclipse.ui.texteditor.spelling.correction.ISpellingCompletionProposal;
35
import org.eclipse.ui.texteditor.spelling.correction.RankedWordProposal;
36
import org.eclipse.ui.texteditor.spelling.correction.WordCorrectionProposal;
37
import org.eclipse.ui.texteditor.spelling.correction.WordIgnoreProposal;
38
import org.eclipse.ui.texteditor.spelling.engine.ISpellCheckEngine;
39
import org.eclipse.ui.texteditor.spelling.engine.ISpellChecker;
40
import org.eclipse.ui.texteditor.spelling.engine.ISpellEvent;
41
import org.eclipse.ui.texteditor.spelling.engine.SpellCheckEngine;
42
43
/**
44
 * A {@link SpellingProblem} that adapts a {@link ISpellEvent}.
45
 * <p>
46
 * TODO: remove {@link ISpellEvent} notification mechanism
47
 * </p>
48
 */
49
50
//this was JavaSpellingProblem
51
public class TextSpellingProblem extends SpellingProblem {
52
53
	/** Spell event */
54
	private ISpellEvent fSpellEvent;
55
56
	/**
57
	 * The associated document.
58
	 *
59
	 * @since 3.3
60
	 */
61
	private IDocument fDocument;
62
63
	/**
64
	 * Initialize with the given spell event.
65
	 *
66
	 * @param spellEvent the spell event
67
	 * @param document the document
68
	 */
69
	public TextSpellingProblem(ISpellEvent spellEvent, IDocument document) {
70
		Assert.isLegal(document != null);
71
		Assert.isLegal(spellEvent != null);
72
		fSpellEvent= spellEvent;
73
		fDocument= document;
74
	}
75
76
	/*
77
	 * @see org.eclipse.ui.texteditor.spelling.SpellingProblem#getOffset()
78
	 */
79
	public int getOffset() {
80
		return fSpellEvent.getBegin();
81
	}
82
83
	/*
84
	 * @see org.eclipse.ui.texteditor.spelling.SpellingProblem#getLength()
85
	 */
86
	public int getLength() {
87
		return fSpellEvent.getEnd() - fSpellEvent.getBegin() + 1;
88
	}
89
90
	/*
91
	 * @see org.eclipse.ui.texteditor.spelling.SpellingProblem#getMessage()
92
	 */
93
	public String getMessage() {
94
		if (isSentenceStart() && isDictionaryMatch())
95
			return Messages.format(SpellingMessages.Spelling_error_case_label, new String[] { fSpellEvent.getWord() });
96
97
		return Messages.format(SpellingMessages.Spelling_error_label, new String[] { fSpellEvent.getWord() });
98
	}
99
100
	/*
101
	 * @see org.eclipse.ui.texteditor.spelling.SpellingProblem#getProposals()
102
	 */
103
	public ICompletionProposal[] getProposals() {
104
		return getProposals(null);
105
	}
106
107
	/*
108
	 * @see org.eclipse.ui.texteditor.spelling.SpellingProblem#getProposals(org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext)
109
	 * @since 3.4
110
	 */
111
	public ICompletionProposal[] getProposals(IQuickAssistInvocationContext context) {
112
		String[] arguments= getArguments();
113
		if (arguments == null)
114
			return new ICompletionProposal[0];
115
116
		if (arguments[0].indexOf('&') != -1 && isIgnoringAmpersand())
117
			return new ICompletionProposal[0]; // no proposals for now
118
119
		final int threshold= PreferenceConstants.getPreferenceStore().getInt(PreferenceConstants.SPELLING_PROPOSAL_THRESHOLD);
120
		int size= 0;
121
		List proposals= null;
122
123
		RankedWordProposal proposal= null;
124
		ISpellingCompletionProposal[] result= null;
125
		int index= 0;
126
127
		boolean fixed= false;
128
		boolean match= false;
129
		boolean sentence= false;
130
131
		final ISpellCheckEngine engine= SpellCheckEngine.getInstance();
132
		final ISpellChecker checker= engine.getSpellChecker();
133
134
		if (checker != null) {
135
136
			if (context == null)
137
				context= new TextInvocationContext(null, getOffset(), getLength());
138
			else
139
				context= new TextInvocationContext(context.getSourceViewer(), getOffset(), getLength());
140
141
			// FIXME: this is a pretty ugly hack
142
			fixed= arguments[0].charAt(0) == IHtmlTagConstants.HTML_TAG_PREFIX
143
					|| arguments[0].charAt(0) == IJavaDocTagConstants.JAVADOC_TAG_PREFIX;
144
145
			if ((sentence && match) && !fixed)
146
				result= new ISpellingCompletionProposal[] { new ChangeCaseProposal(
147
						arguments, getOffset(), getLength(), context, engine
148
								.getLocale()) };
149
			else {
150
151
				proposals= new ArrayList(checker.getProposals(arguments[0],
152
						sentence));
153
				size= proposals.size();
154
155
				if (threshold > 0 && size > threshold) {
156
157
					Collections.sort(proposals);
158
					proposals= proposals
159
							.subList(size - threshold - 1, size - 1);
160
					size= proposals.size();
161
				}
162
163
				boolean extendable= !fixed ? (checker.acceptsWords() || AddWordProposal.canAskToConfigure()) : false;
164
				result= new ISpellingCompletionProposal[size + (extendable ? 3 : 2)];
165
166
				for (index= 0; index < size; index++) {
167
168
					proposal= (RankedWordProposal) proposals.get(index);
169
					result[index]= new WordCorrectionProposal(proposal
170
							.getText(), arguments, getOffset(), getLength(),
171
							context, proposal.getRank());
172
				}
173
174
				if (extendable)
175
					result[index++]= new AddWordProposal(arguments[0], context);
176
177
				result[index++]= new WordIgnoreProposal(arguments[0], context);
178
				result[index++]= new DisableSpellCheckingProposal(context);
179
			}
180
		}
181
182
		return result;
183
	}
184
185
	private boolean isIgnoringAmpersand() {
186
		return PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.SPELLING_IGNORE_AMPERSAND_IN_PROPERTIES);
187
	}
188
189
	public String[] getArguments() {
190
191
		String prefix= ""; //$NON-NLS-1$
192
		String postfix= ""; //$NON-NLS-1$
193
		String word;
194
		try {
195
			word= fDocument.get(getOffset(), getLength());
196
		} catch (BadLocationException e) {
197
			return null;
198
		}
199
200
		try {
201
202
			IRegion line= fDocument.getLineInformationOfOffset(getOffset());
203
			prefix= fDocument.get(line.getOffset(), getOffset() - line.getOffset());
204
			int postfixStart= getOffset() + getLength();
205
			postfix= fDocument.get(postfixStart, line.getOffset() + line.getLength() - postfixStart);
206
207
		} catch (BadLocationException exception) {
208
			// Do nothing
209
		}
210
		return new String[] {
211
				word,
212
				prefix,
213
				postfix,
214
				isSentenceStart() ? Boolean.toString(true) : Boolean
215
						.toString(false),
216
				isDictionaryMatch() ? Boolean.toString(true) : Boolean
217
						.toString(false) };
218
	}
219
220
	/**
221
	 * Returns <code>true</code> iff the corresponding word was found in the dictionary.
222
	 * <p>
223
	 * NOTE: to be removed, see {@link #getProposals()}
224
	 * </p>
225
	 *
226
	 * @return <code>true</code> iff the corresponding word was found in the dictionary
227
	 */
228
	public boolean isDictionaryMatch() {
229
		return fSpellEvent.isMatch();
230
	}
231
232
	/**
233
	 * Returns <code>true</code> iff the corresponding word starts a sentence.
234
	 * <p>
235
	 * NOTE: to be removed, see {@link #getProposals()}
236
	 * </p>
237
	 *
238
	 * @return <code>true</code> iff the corresponding word starts a sentence
239
	 */
240
	public boolean isSentenceStart() {
241
		return fSpellEvent.isStart();
242
	}
243
244
}
(-)src/org/eclipse/ui/texteditor/spelling/correction/AddWordProposal.java (+169 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.texteditor.spelling.correction;
13
14
import org.eclipse.swt.graphics.Image;
15
import org.eclipse.swt.graphics.Point;
16
import org.eclipse.swt.widgets.Shell;
17
18
import org.eclipse.jface.dialogs.IDialogConstants;
19
import org.eclipse.jface.dialogs.MessageDialogWithToggle;
20
21
import org.eclipse.jface.text.IDocument;
22
import org.eclipse.jface.text.contentassist.IContextInformation;
23
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
24
25
import org.eclipse.ui.dialogs.PreferencesUtil;
26
import org.eclipse.ui.internal.texteditor.spelling.Messages;
27
import org.eclipse.ui.internal.texteditor.spelling.SpellingMessages;
28
29
import org.eclipse.ui.texteditor.spelling.PreferenceConstants;
30
import org.eclipse.ui.texteditor.spelling.SpellingProblem;
31
import org.eclipse.ui.texteditor.spelling.engine.ISpellCheckEngine;
32
import org.eclipse.ui.texteditor.spelling.engine.ISpellChecker;
33
import org.eclipse.ui.texteditor.spelling.engine.SpellCheckEngine;
34
/**
35
 * Proposal to add the unknown word to the dictionaries.
36
 *
37
 * @since 3.0
38
 */
39
public class AddWordProposal implements ISpellingCompletionProposal {
40
41
	private static final String PREF_KEY_DO_NOT_ASK= "do_not_ask_to_install_user_dictionary"; //$NON-NLS-1$
42
43
	/** The invocation context */
44
	private final IQuickAssistInvocationContext fContext;
45
46
	/** The word to add */
47
	private final String fWord;
48
49
50
	/**
51
	 * Creates a new add word proposal
52
	 *
53
	 * @param word
54
	 *                   The word to add
55
	 * @param context
56
	 *                   The invocation context
57
	 */
58
	public AddWordProposal(final String word, final IQuickAssistInvocationContext context) {
59
		fContext= context;
60
		fWord= word;
61
	}
62
63
	/*
64
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(org.eclipse.jface.text.IDocument)
65
	 */
66
	public final void apply(final IDocument document) {
67
68
		final ISpellCheckEngine engine= SpellCheckEngine.getInstance();
69
		final ISpellChecker checker= engine.getSpellChecker();
70
71
		if (checker == null)
72
			return;
73
74
		if (!checker.acceptsWords()) {
75
			Shell shell= null;
76
			if (fContext != null && fContext.getSourceViewer() != null)
77
				shell= fContext.getSourceViewer().getTextWidget().getShell();
78
79
			/*else
80
				shell= JavaPlugin.getActiveWorkbenchShell();*///TODO: fix this, this code is needed
81
82
			if (!canAskToConfigure() || !askUserToConfigureUserDictionary(shell))
83
				return;
84
85
			String[] preferencePageIds= new String[] { "org.eclipse.ui.editors.preferencePages.Spelling" }; //$NON-NLS-1$
86
			PreferencesUtil.createPreferenceDialogOn(shell, preferencePageIds[0], preferencePageIds, null).open();
87
		}
88
89
		if (checker.acceptsWords()) {
90
			checker.addWord(fWord);
91
			if (fContext != null && fContext.getSourceViewer() != null)
92
				SpellingProblem.removeAll(fContext.getSourceViewer(), fWord);
93
		}
94
	}
95
96
	/**
97
	 * Asks the user whether he wants to configure a user dictionary.
98
	 * 
99
	 * @param shell the shell
100
	 * @return <code>true</code> if the user wants to configure the user dictionary
101
	 * @since 3.3
102
	 */
103
	private boolean askUserToConfigureUserDictionary(Shell shell) {
104
		MessageDialogWithToggle toggleDialog= MessageDialogWithToggle.openYesNoQuestion(
105
				shell,
106
				SpellingMessages.Spelling_add_askToConfigure_title,
107
				SpellingMessages.Spelling_add_askToConfigure_question,
108
				SpellingMessages.Spelling_add_askToConfigure_ignoreMessage,
109
				false,
110
				null,
111
				null);
112
113
		PreferenceConstants.getPreferenceStore().setValue(PREF_KEY_DO_NOT_ASK, toggleDialog.getToggleState());
114
115
		return toggleDialog.getReturnCode() == IDialogConstants.YES_ID;
116
	}
117
118
	/**
119
	 * Tells whether this proposal can ask to
120
	 * configure a user dictionary.
121
	 *
122
	 * @return <code>true</code> if it can ask the user
123
	 */
124
	public static boolean canAskToConfigure() {
125
		return !PreferenceConstants.getPreferenceStore().getBoolean(PREF_KEY_DO_NOT_ASK);
126
	}
127
128
	/*
129
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo()
130
	 */
131
	public String getAdditionalProposalInfo() {
132
		return Messages.format(SpellingMessages.Spelling_add_info, new String[] { WordCorrectionProposal.getHtmlRepresentation(fWord) });
133
	}
134
135
	/*
136
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getContextInformation()
137
	 */
138
	public final IContextInformation getContextInformation() {
139
		return null;
140
	}
141
142
	/*
143
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString()
144
	 */
145
	public String getDisplayString() {
146
		return Messages.format(SpellingMessages.Spelling_add_label, new String[] { fWord });
147
	}
148
149
	/*
150
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage()
151
	 */
152
	public Image getImage() {
153
		return JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_ADD);
154
	}
155
156
	/*
157
	 * @see org.eclipse.jdt.ui.text.java.IJavaCompletionProposal#getRelevance()
158
	 */
159
	public int getRelevance() {
160
		return Integer.MIN_VALUE;
161
	}
162
163
	/*
164
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getSelection(org.eclipse.jface.text.IDocument)
165
	 */
166
	public final Point getSelection(final IDocument document) {
167
		return new Point(fContext.getOffset(), fContext.getLength());
168
	}
169
}
(-)src/org/eclipse/ui/texteditor/spelling/correction/ChangeCaseProposal.java (+46 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.texteditor.spelling.correction;
13
14
import java.util.Locale;
15
16
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
17
18
import org.eclipse.ui.internal.texteditor.spelling.SpellingMessages;
19
20
/**
21
 * Proposal to change the letter case of a word.
22
 *
23
 * @since 3.0
24
 */
25
public class ChangeCaseProposal extends WordCorrectionProposal {
26
27
	/**
28
	 * Creates a new change case proposal.
29
	 * 
30
	 * @param arguments The problem arguments associated with the spelling problem
31
	 * @param offset The offset in the document where to apply the proposal
32
	 * @param length The length in the document to apply the proposal
33
	 * @param context The invocation context for this proposal
34
	 * @param locale The locale to use for the case change
35
	 */
36
	public ChangeCaseProposal(final String[] arguments, final int offset, final int length, final IQuickAssistInvocationContext context, final Locale locale) {
37
		super(Character.isLowerCase(arguments[0].charAt(0)) ? Character.toUpperCase(arguments[0].charAt(0)) + arguments[0].substring(1) : arguments[0], arguments, offset, length, context, Integer.MAX_VALUE);
38
	}
39
40
	/*
41
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString()
42
	 */
43
	public String getDisplayString() {
44
		return SpellingMessages.Spelling_case_label;
45
	}
46
}
(-)src/org/eclipse/ui/texteditor/spelling/correction/DisableSpellCheckingProposal.java (+97 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2007, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.texteditor.spelling.correction;
12
13
import org.eclipse.swt.graphics.Image;
14
import org.eclipse.swt.graphics.Point;
15
16
import org.eclipse.jface.preference.IPreferenceStore;
17
18
import org.eclipse.jface.text.IDocument;
19
import org.eclipse.jface.text.contentassist.IContextInformation;
20
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
21
22
import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
23
import org.eclipse.ui.internal.texteditor.spelling.SpellingMessages;
24
25
import org.eclipse.ui.texteditor.spelling.SpellingService;
26
27
28
29
/**
30
 * Proposal to disable spell checking.
31
 *
32
 * @since 3.3
33
 */
34
public class DisableSpellCheckingProposal implements ISpellingCompletionProposal {
35
36
	/** The invocation context */
37
	private IQuickAssistInvocationContext fContext;
38
39
	/**
40
	 * Creates a new proposal.
41
	 *
42
	 * @param context the invocation context
43
	 */
44
	public DisableSpellCheckingProposal(IQuickAssistInvocationContext context) {
45
		fContext= context;
46
	}
47
48
	/*
49
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(org.eclipse.jface.text.IDocument)
50
	 */
51
	public final void apply(final IDocument document) {
52
		//IPreferenceStore store= EditorsUI.getPreferenceStore();
53
		IPreferenceStore store= TextEditorPlugin.getDefault().getPreferenceStore(); //TODO : is this good?
54
		store.setValue(SpellingService.PREFERENCE_SPELLING_ENABLED, false);
55
	}
56
57
	/*
58
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo()
59
	 */
60
	public String getAdditionalProposalInfo() {
61
		return SpellingMessages.Spelling_disable_info;
62
	}
63
64
	/*
65
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getContextInformation()
66
	 */
67
	public final IContextInformation getContextInformation() {
68
		return null;
69
	}
70
71
	/*
72
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString()
73
	 */
74
	public String getDisplayString() {
75
		return SpellingMessages.Spelling_disable_label;
76
	}
77
78
	/*
79
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage()
80
	 */
81
	public Image getImage() {
82
		return JavaPluginImages.get(JavaPluginImages.IMG_OBJS_NLS_NEVER_TRANSLATE);
83
	}
84
	/*
85
	 * @see org.eclipse.jdt.ui.text.java.IJavaCompletionProposal#getRelevance()
86
	 */
87
	public final int getRelevance() {
88
		return Integer.MIN_VALUE + 1;
89
	}
90
91
	/*
92
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getSelection(org.eclipse.jface.text.IDocument)
93
	 */
94
	public final Point getSelection(final IDocument document) {
95
		return new Point(fContext.getOffset(), fContext.getLength());
96
	}
97
}
(-)src/org/eclipse/ui/texteditor/spelling/correction/IHtmlTagConstants.java (+51 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.texteditor.spelling.correction;
13
14
/**
15
 * Html tag constants.
16
 *
17
 * @since 3.0
18
 */
19
20
//XXX Duplicated from JDT
21
public interface IHtmlTagConstants {
22
23
	/** Html tag close prefix */
24
	public static final String HTML_CLOSE_PREFIX= "</"; //$NON-NLS-1$
25
26
	/** Html entity characters */
27
	public static final char[] HTML_ENTITY_CHARACTERS= new char[] { '<', '>', ' ', '&', '^', '~', '\"' };
28
29
	/**
30
	 * Html entity start.
31
	 * @since 3.3
32
	 */
33
	public static final char HTML_ENTITY_START= '&';
34
	/**
35
	 * Html entity end.
36
	 * @since 3.3
37
	 */
38
	public static final char HTML_ENTITY_END= ';';
39
40
	/** Html entity codes */
41
	public static final String[] HTML_ENTITY_CODES= new String[] { "&lt;", "&gt;", "&nbsp;", "&amp;", "&circ;", "&tilde;", "&quot;" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
42
43
	/** Html general tags */
44
	public static final String[] HTML_GENERAL_TAGS= new String[] { "a", "b", "blockquote", "br", "code", "dd", "dl", "dt", "em", "hr", "h1", "h2", "h3", "h4", "h5", "h6", "i", "li", "nl", "ol", "p", "pre", "q", "strong", "tbody", "td", "th", "tr", "tt", "ul" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$ //$NON-NLS-13$ //$NON-NLS-14$ //$NON-NLS-15$ //$NON-NLS-16$ //$NON-NLS-17$ //$NON-NLS-18$ //$NON-NLS-19$ //$NON-NLS-20$ //$NON-NLS-21$ //$NON-NLS-22$ //$NON-NLS-23$ //$NON-NLS-24$ //$NON-NLS-25$ //$NON-NLS-26$ //$NON-NLS-27$ //$NON-NLS-28$ //$NON-NLS-29$ //$NON-NLS-30$
45
46
	/** Html tag postfix */
47
	public static final char HTML_TAG_POSTFIX= '>';
48
49
	/** Html tag prefix */
50
	public static final char HTML_TAG_PREFIX= '<';
51
}
(-)src/org/eclipse/ui/texteditor/spelling/correction/IJavaDocTagConstants.java (+38 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.texteditor.spelling.correction;
12
13
14
/**
15
 * Javadoc tag constants.
16
 *
17
 * @since 3.0
18
 */
19
20
//XXX duplicated from JDT : it must not be here though. delete this in the end
21
public interface IJavaDocTagConstants {
22
23
24
	/** Javadoc link tags */
25
	public static final String[] JAVADOC_LINK_TAGS= new String[] { "@docRoot", "@inheritDoc", "@link", "@linkplain" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
26
27
	/** Javadoc parameter tags */
28
	public static final String[] JAVADOC_PARAM_TAGS= new String[] { "@exception", "@param", "@serialField", "@throws"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
29
30
	/** Javadoc reference tags */
31
	public static final String[] JAVADOC_REFERENCE_TAGS= new String[] { "@see" }; //$NON-NLS-1$
32
33
	/** Javadoc root tags */
34
	public static final String[] JAVADOC_ROOT_TAGS= new String[] { "@author", "@deprecated", "@return", "@see", "@serial", "@serialData", "@since", "@version", "@inheritDoc", "@category", "@value", "@literal", "@code", "@noinstantiate", "@noreference", "@noimplement", "@noextend", "@nooverride" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$ //$NON-NLS-13$ //$NON-NLS-14$ //$NON-NLS-15$ //$NON-NLS-16$ //$NON-NLS-17$ //$NON-NLS-18$
35
36
	/** Javadoc tag prefix */
37
	public static final char JAVADOC_TAG_PREFIX= '@';
38
}
(-)src/org/eclipse/ui/texteditor/spelling/correction/ISpellingCompletionProposal.java (+40 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.texteditor.spelling.correction;
12
13
import org.eclipse.jface.text.contentassist.ICompletionProposal;
14
15
/**
16
 * A completion proposal with a relevance value.
17
 * The relevance value is used to sort the completion proposals. Proposals with higher relevance
18
 * should be listed before proposals with lower relevance.
19
 * <p>
20
 * This interface can be implemented by clients.
21
 * </p>
22
 *
23
 * @see org.eclipse.jface.text.contentassist.ICompletionProposal
24
 * @since 2.1
25
 */
26
27
//TODO: copied from IJavaCompletionProposal
28
public interface ISpellingCompletionProposal extends ICompletionProposal {
29
30
	/**
31
	 * Returns the relevance of this completion proposal.
32
	 * <p>
33
	 * The relevance is used to determine if this proposal is more
34
	 * relevant than another proposal.</p>
35
	 *
36
	 * @return the relevance of this completion proposal in the range of [0, 100]
37
	 */
38
	int getRelevance();
39
40
}
(-)src/org/eclipse/ui/texteditor/spelling/correction/JavaPluginImages.java (+246 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *     Ferenc Hechler, ferenc_hechler@users.sourceforge.net - 83258 [jar exporter] Deploy java application as executable jar
11
 *******************************************************************************/
12
package org.eclipse.ui.texteditor.spelling.correction;
13
14
import java.net.URL;
15
import java.util.HashMap;
16
import java.util.Iterator;
17
18
import org.osgi.framework.Bundle;
19
20
import org.eclipse.swt.graphics.Image;
21
import org.eclipse.swt.graphics.ImageData;
22
23
import org.eclipse.core.runtime.FileLocator;
24
import org.eclipse.core.runtime.IPath;
25
import org.eclipse.core.runtime.Path;
26
27
import org.eclipse.jface.action.IAction;
28
import org.eclipse.jface.resource.ImageDescriptor;
29
import org.eclipse.jface.resource.ImageRegistry;
30
31
import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
32
33
34
/**
35
 * Bundle of most images used by the Java plug-in.
36
 */
37
public class JavaPluginImages {
38
39
	public static final IPath ICONS_PATH= new Path("$nl$/icons/full"); //$NON-NLS-1$
40
41
	private static final String NAME_PREFIX= "org.eclipse.jdt.ui."; //$NON-NLS-1$
42
	private static final int    NAME_PREFIX_LENGTH= NAME_PREFIX.length();
43
44
	// The plug-in registry
45
	private static ImageRegistry fgImageRegistry= null;
46
	private static HashMap fgAvoidSWTErrorMap= null;
47
48
	private static final String T_OBJ= "obj16"; 		//$NON-NLS-1$
49
	private static final String T_OVR= "ovr16"; 		//$NON-NLS-1$
50
	private static final String T_WIZBAN= "wizban"; 	//$NON-NLS-1$
51
	private static final String T_ELCL= "elcl16"; 	//$NON-NLS-1$
52
	private static final String T_DLCL= "dlcl16"; 	//$NON-NLS-1$
53
	private static final String T_ETOOL= "etool16"; 	//$NON-NLS-1$
54
	private static final String T_EVIEW= "eview16"; //$NON-NLS-1$
55
56
57
	// Keys for correction proposal. We have to put the image into the registry since "code assist" doesn't
58
	// have a life cycle. So no chance to dispose icons.
59
60
	public static final String IMG_CORRECTION_CHANGE= NAME_PREFIX + "correction_change.gif"; //$NON-NLS-1$
61
	public static final String IMG_CORRECTION_MOVE= NAME_PREFIX + "correction_move.gif"; //$NON-NLS-1$
62
	public static final String IMG_CORRECTION_RENAME= NAME_PREFIX + "correction_rename.gif"; //$NON-NLS-1$
63
	public static final String IMG_CORRECTION_LINKED_RENAME= NAME_PREFIX + "correction_linked_rename.gif"; //$NON-NLS-1$
64
	public static final String IMG_CORRECTION_DELETE_IMPORT= NAME_PREFIX + "correction_delete_import.gif"; //$NON-NLS-1$
65
	public static final String IMG_CORRECTION_LOCAL= NAME_PREFIX + "localvariable_obj.gif"; //$NON-NLS-1$
66
	public static final String IMG_CORRECTION_REMOVE= NAME_PREFIX + "remove_correction.gif"; //$NON-NLS-1$
67
	public static final String IMG_CORRECTION_ADD= NAME_PREFIX + "add_correction.gif"; //$NON-NLS-1$
68
	public static final String IMG_CORRECTION_CAST= NAME_PREFIX + "correction_cast.gif"; //$NON-NLS-1$
69
	public static final String IMG_CORRECTION_MULTI_FIX= NAME_PREFIX + "correction_multi_fix.gif"; //$NON-NLS-1$
70
71
72
	public static final String IMG_OBJS_NLS_TRANSLATE= NAME_PREFIX + "translate.gif"; //$NON-NLS-1$
73
	public static final String IMG_OBJS_NLS_NEVER_TRANSLATE= NAME_PREFIX + "never_translate.gif"; //$NON-NLS-1$
74
	public static final String IMG_OBJS_NLS_SKIP= NAME_PREFIX + "skip.gif"; //$NON-NLS-1$
75
76
	static {
77
		createManagedFromKey(T_OBJ, IMG_CORRECTION_CHANGE);
78
		createManagedFromKey(T_OBJ, IMG_CORRECTION_MOVE);
79
		createManagedFromKey(T_OBJ, IMG_CORRECTION_RENAME);
80
		createManagedFromKey(T_OBJ, IMG_CORRECTION_LINKED_RENAME);
81
		createManagedFromKey(T_OBJ, IMG_CORRECTION_DELETE_IMPORT);
82
		createManagedFromKey(T_OBJ, IMG_CORRECTION_LOCAL);
83
		createManagedFromKey(T_OBJ, IMG_CORRECTION_REMOVE);
84
		createManagedFromKey(T_OBJ, IMG_CORRECTION_ADD);
85
		createManagedFromKey(T_OBJ, IMG_CORRECTION_CAST);
86
		createManagedFromKey(T_OBJ, IMG_CORRECTION_MULTI_FIX);
87
	}
88
89
	private static final class CachedImageDescriptor extends ImageDescriptor {
90
		private ImageDescriptor fDescriptor;
91
		private ImageData fData;
92
93
		public CachedImageDescriptor(ImageDescriptor descriptor) {
94
			fDescriptor = descriptor;
95
		}
96
97
		public ImageData getImageData() {
98
			if (fData == null) {
99
				fData= fDescriptor.getImageData();
100
			}
101
			return fData;
102
		}
103
	}
104
105
	/**
106
	 * Returns the image managed under the given key in this registry.
107
	 *
108
	 * @param key the image's key
109
	 * @return the image managed under the given key
110
	 */
111
	public static Image get(String key) {
112
		return getImageRegistry().get(key);
113
	}
114
115
	/**
116
	 * Returns the image descriptor for the given key in this registry. Might be called in a non-UI thread.
117
	 *
118
	 * @param key the image's key
119
	 * @return the image descriptor for the given key
120
	 */
121
	public static ImageDescriptor getDescriptor(String key) {
122
		if (fgImageRegistry == null) {
123
			return (ImageDescriptor) fgAvoidSWTErrorMap.get(key);
124
		}
125
		return getImageRegistry().getDescriptor(key);
126
	}
127
128
	/**
129
	 * Sets the three image descriptors for enabled, disabled, and hovered to an action. The actions
130
	 * are retrieved from the *tool16 folders.
131
	 *
132
	 * @param action	the action
133
	 * @param iconName	the icon name
134
	 */
135
	public static void setToolImageDescriptors(IAction action, String iconName) {
136
		setImageDescriptors(action, "tool16", iconName); //$NON-NLS-1$
137
	}
138
139
	/**
140
	 * Sets the three image descriptors for enabled, disabled, and hovered to an action. The actions
141
	 * are retrieved from the *lcl16 folders.
142
	 *
143
	 * @param action	the action
144
	 * @param iconName	the icon name
145
	 */
146
	public static void setLocalImageDescriptors(IAction action, String iconName) {
147
		setImageDescriptors(action, "lcl16", iconName); //$NON-NLS-1$
148
	}
149
150
	/*
151
	 * Helper method to access the image registry from the JavaPlugin class.
152
	 */
153
	/* package */ static ImageRegistry getImageRegistry() {
154
		if (fgImageRegistry == null) {
155
			fgImageRegistry= new ImageRegistry();
156
			for (Iterator iter= fgAvoidSWTErrorMap.keySet().iterator(); iter.hasNext();) {
157
				String key= (String) iter.next();
158
				fgImageRegistry.put(key, (ImageDescriptor) fgAvoidSWTErrorMap.get(key));
159
			}
160
			fgAvoidSWTErrorMap= null;
161
		}
162
		return fgImageRegistry;
163
	}
164
165
	//---- Helper methods to access icons on the file system --------------------------------------
166
167
	private static void setImageDescriptors(IAction action, String type, String relPath) {
168
		ImageDescriptor id= create("d" + type, relPath, false); //$NON-NLS-1$
169
		if (id != null)
170
			action.setDisabledImageDescriptor(id);
171
172
		/*
173
		 * id= create("c" + type, relPath, false); //$NON-NLS-1$
174
		 * if (id != null)
175
		 * 		action.setHoverImageDescriptor(id);
176
		 */
177
178
		ImageDescriptor descriptor= create("e" + type, relPath, true); //$NON-NLS-1$
179
		action.setHoverImageDescriptor(descriptor);
180
		action.setImageDescriptor(descriptor);
181
	}
182
183
	private static ImageDescriptor createManagedFromKey(String prefix, String key) {
184
		return createManaged(prefix, key.substring(NAME_PREFIX_LENGTH), key);
185
	}
186
187
	private static ImageDescriptor createManaged(String prefix, String name, String key) {
188
		ImageDescriptor result= create(prefix, name, true);
189
190
		if (fgAvoidSWTErrorMap == null) {
191
			fgAvoidSWTErrorMap= new HashMap();
192
		}
193
		fgAvoidSWTErrorMap.put(key, result);
194
		if (fgImageRegistry != null) {
195
			TextEditorPlugin.logErrorMessage("Image registry already defined"); //$NON-NLS-1$
196
		}
197
		return result;
198
	}
199
200
	/*
201
	 * Creates an image descriptor for the given prefix and name in the JDT UI bundle. The path can
202
	 * contain variables like $NL$.
203
	 * If no image could be found, <code>useMissingImageDescriptor</code> decides if either
204
	 * the 'missing image descriptor' is returned or <code>null</code>.
205
	 * or <code>null</code>.
206
	 */
207
	private static ImageDescriptor create(String prefix, String name, boolean useMissingImageDescriptor) {
208
		IPath path= ICONS_PATH.append(prefix).append(name);
209
		return createImageDescriptor(TextEditorPlugin.getDefault().getBundle(), path, useMissingImageDescriptor);
210
	}
211
212
	/*
213
	 * Creates an image descriptor for the given prefix and name in the JDT UI bundle. The path can
214
	 * contain variables like $NL$.
215
	 * If no image could be found, the 'missing image descriptor' is returned.
216
	 */
217
	private static ImageDescriptor createUnManaged(String prefix, String name) {
218
		return create(prefix, name, true);
219
	}
220
221
	/*
222
	 * Creates an image descriptor for the given prefix and name in the JDT UI bundle and let type descriptor cache the image data.
223
	 * If no image could be found, the 'missing image descriptor' is returned.
224
	 */
225
	private static ImageDescriptor createUnManagedCached(String prefix, String name) {
226
		return new CachedImageDescriptor(create(prefix, name, true));
227
	}
228
229
	/*
230
	 * Creates an image descriptor for the given path in a bundle. The path can contain variables
231
	 * like $NL$.
232
	 * If no image could be found, <code>useMissingImageDescriptor</code> decides if either
233
	 * the 'missing image descriptor' is returned or <code>null</code>.
234
	 * Added for 3.1.1.
235
	 */
236
	public static ImageDescriptor createImageDescriptor(Bundle bundle, IPath path, boolean useMissingImageDescriptor) {
237
		URL url= FileLocator.find(bundle, path, null);
238
		if (url != null) {
239
			return ImageDescriptor.createFromURL(url);
240
		}
241
		if (useMissingImageDescriptor) {
242
			return ImageDescriptor.getMissingImageDescriptor();
243
		}
244
		return null;
245
	}
246
}
(-)src/org/eclipse/ui/texteditor/spelling/correction/NoCompletionsProposal.java (+74 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.texteditor.spelling.correction;
12
13
import org.eclipse.swt.graphics.Image;
14
import org.eclipse.swt.graphics.Point;
15
16
import org.eclipse.jface.text.IDocument;
17
import org.eclipse.jface.text.contentassist.ICompletionProposal;
18
import org.eclipse.jface.text.contentassist.IContextInformation;
19
20
import org.eclipse.ui.internal.texteditor.spelling.SpellingMessages;
21
22
/**
23
 * Proposal telling that there are no proposals available.
24
 * <p>
25
 * Applying this proposal does nothing.
26
 * </p>
27
 *
28
 * @since 3.3
29
 */
30
public final class NoCompletionsProposal implements ICompletionProposal {
31
32
	/*
33
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(org.eclipse.jface.text.IDocument)
34
	 */
35
	public void apply(IDocument document) {
36
		// do nothing
37
	}
38
39
	/*
40
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo()
41
	 */
42
	public String getAdditionalProposalInfo() {
43
		return null;
44
	}
45
46
	/*
47
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getContextInformation()
48
	 */
49
	public IContextInformation getContextInformation() {
50
		return null;
51
	}
52
53
	/*
54
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString()
55
	 */
56
	public String getDisplayString() {
57
			return SpellingMessages.NoCompletionsProposal_displayString;
58
		}
59
60
	/*
61
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage()
62
	 */
63
	public Image getImage() {
64
		return null;
65
	}
66
67
	/*
68
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getSelection(org.eclipse.jface.text.IDocument)
69
	 */
70
	public Point getSelection(IDocument document) {
71
		return null;
72
	}
73
74
}
(-)src/org/eclipse/ui/texteditor/spelling/correction/RankedWordProposal.java (+102 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.texteditor.spelling.correction;
13
14
/**
15
 * Ranked word proposal for quick fix and content assist.
16
 *
17
 * @since 3.0
18
 */
19
public class RankedWordProposal implements Comparable {
20
21
	/** The word rank */
22
	private int fRank;
23
24
	/** The word text */
25
	private final String fText;
26
27
	/**
28
	 * Creates a new ranked word proposal.
29
	 *
30
	 * @param text
31
	 *                   The text of this proposal
32
	 * @param rank
33
	 *                   The rank of this proposal
34
	 */
35
	public RankedWordProposal(final String text, final int rank) {
36
		fText= text;
37
		fRank= rank;
38
	}
39
40
	/*
41
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
42
	 */
43
	public final int compareTo(Object object) {
44
45
		final RankedWordProposal word= (RankedWordProposal)object;
46
		final int rank= word.getRank();
47
48
		if (fRank < rank)
49
			return -1;
50
51
		if (fRank > rank)
52
			return 1;
53
54
		return 0;
55
	}
56
57
	/*
58
	 * @see java.lang.Object#equals(java.lang.Object)
59
	 */
60
	public final boolean equals(Object object) {
61
62
		if (object instanceof RankedWordProposal)
63
			return object.hashCode() == hashCode();
64
65
		return false;
66
	}
67
68
	/**
69
	 * Returns the rank of the word
70
	 *
71
	 * @return The rank of the word
72
	 */
73
	public final int getRank() {
74
		return fRank;
75
	}
76
77
	/**
78
	 * Returns the text of this word.
79
	 *
80
	 * @return The text of this word
81
	 */
82
	public final String getText() {
83
		return fText;
84
	}
85
86
	/*
87
	 * @see java.lang.Object#hashCode()
88
	 */
89
	public final int hashCode() {
90
		return fText.hashCode();
91
	}
92
93
	/**
94
	 * Sets the rank of the word.
95
	 *
96
	 * @param rank
97
	 *                   The rank to set
98
	 */
99
	public final void setRank(final int rank) {
100
		fRank= rank;
101
	}
102
}
(-)src/org/eclipse/ui/texteditor/spelling/correction/SpellingCorrectionProcessor.java (+121 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006, 2009 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.texteditor.spelling.correction;
12
13
import java.util.ArrayList;
14
import java.util.Arrays;
15
import java.util.Iterator;
16
import java.util.List;
17
18
import org.eclipse.jface.text.Position;
19
import org.eclipse.jface.text.contentassist.ICompletionProposal;
20
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
21
import org.eclipse.jface.text.quickassist.IQuickAssistProcessor;
22
import org.eclipse.jface.text.source.Annotation;
23
import org.eclipse.jface.text.source.IAnnotationModel;
24
import org.eclipse.jface.text.source.ISourceViewer;
25
import org.eclipse.jface.text.source.TextInvocationContext;
26
27
import org.eclipse.ui.texteditor.spelling.SpellingAnnotation;
28
import org.eclipse.ui.texteditor.spelling.SpellingProblem;
29
30
31
32
/**
33
 * Spelling correction processor used to show quick
34
 * fixes for spelling problems.
35
 *
36
 * @since 3.3
37
 */
38
public final class SpellingCorrectionProcessor implements IQuickAssistProcessor {
39
40
41
	private static final ICompletionProposal[] fgNoSuggestionsProposal=  new ICompletionProposal[] { new NoCompletionsProposal() };
42
43
44
	/*
45
	 * @see IContentAssistProcessor#computeCompletionProposals(ITextViewer, int)
46
	 */
47
	public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationContext quickAssistContext) {
48
		ISourceViewer viewer= quickAssistContext.getSourceViewer();
49
		int documentOffset= quickAssistContext.getOffset();
50
51
		int length= viewer != null ? viewer.getSelectedRange().y : -1;
52
		TextInvocationContext context= new TextInvocationContext(viewer, documentOffset, length);
53
54
55
		IAnnotationModel model= viewer.getAnnotationModel();
56
		if (model == null)
57
			return fgNoSuggestionsProposal;
58
59
		List proposals= computeProposals(context, model);
60
		if (proposals.isEmpty())
61
			return fgNoSuggestionsProposal;
62
63
		return (ICompletionProposal[]) proposals.toArray(new ICompletionProposal[proposals.size()]);
64
	}
65
66
	private boolean isAtPosition(int offset, Position pos) {
67
		return (pos != null) && (offset >= pos.getOffset() && offset <= (pos.getOffset() +  pos.getLength()));
68
	}
69
70
	private List computeProposals(IQuickAssistInvocationContext context, IAnnotationModel model) {
71
		int offset= context.getOffset();
72
		ArrayList annotationList= new ArrayList();
73
		Iterator iter= model.getAnnotationIterator();
74
		while (iter.hasNext()) {
75
			Annotation annotation= (Annotation)iter.next();
76
			if (canFix(annotation)) {
77
				Position pos= model.getPosition(annotation);
78
				if (isAtPosition(offset, pos)) {
79
					collectSpellingProblems(annotation, annotationList);
80
				}
81
			}
82
		}
83
		SpellingProblem[] spellingProblems= (SpellingProblem[]) annotationList.toArray(new SpellingProblem[annotationList.size()]);
84
		return computeProposals(context, spellingProblems);
85
	}
86
87
	private void collectSpellingProblems(Annotation annotation, List problems) {
88
		if (annotation instanceof SpellingAnnotation)
89
			problems.add(((SpellingAnnotation)annotation).getSpellingProblem());
90
	}
91
92
	private List computeProposals(IQuickAssistInvocationContext context, SpellingProblem[] spellingProblems) {
93
		List proposals= new ArrayList();
94
		for (int i= 0; i < spellingProblems.length; i++)
95
			proposals.addAll(Arrays.asList(spellingProblems[i].getProposals(context)));
96
97
		return proposals;
98
	}
99
100
	/*
101
	 * @see IContentAssistProcessor#getErrorMessage()
102
	 */
103
	public String getErrorMessage() {
104
		return null;
105
	}
106
107
	/*
108
	 * @see org.eclipse.jface.text.quickassist.IQuickAssistProcessor#canFix(org.eclipse.jface.text.source.Annotation)
109
	 */
110
	public boolean canFix(Annotation annotation) {
111
		return annotation instanceof SpellingAnnotation && !annotation.isMarkedDeleted();
112
	}
113
114
	/*
115
	 * @see org.eclipse.jface.text.quickassist.IQuickAssistProcessor#canAssist(org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext)
116
	 */
117
	public boolean canAssist(IQuickAssistInvocationContext invocationContext) {
118
		return false;
119
	}
120
121
}
(-)src/org/eclipse/ui/texteditor/spelling/correction/WordCorrectionProposal.java (+173 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.texteditor.spelling.correction;
13
14
import org.eclipse.swt.graphics.Image;
15
import org.eclipse.swt.graphics.Point;
16
17
import org.eclipse.jface.text.BadLocationException;
18
import org.eclipse.jface.text.IDocument;
19
import org.eclipse.jface.text.contentassist.IContextInformation;
20
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
21
22
import org.eclipse.ui.internal.texteditor.spelling.Messages;
23
import org.eclipse.ui.internal.texteditor.spelling.SpellingMessages;
24
25
/**
26
 * Proposal to correct the incorrectly spelled word.
27
 *
28
 * @since 3.0
29
 */
30
public class WordCorrectionProposal implements ISpellingCompletionProposal {
31
32
	/**
33
	 * Returns the html representation of the specified string.
34
	 *
35
	 * @param string
36
	 *                   The string to return the html representation for
37
	 * @return The html representation for the string
38
	 */
39
	public static String getHtmlRepresentation(final String string) {
40
41
		final int length= string.length();
42
		final StringBuffer buffer= new StringBuffer(string);
43
44
		for (int offset= length - 1; offset >= 0; offset--) {
45
46
			for (int index= 0; index < IHtmlTagConstants.HTML_ENTITY_CHARACTERS.length; index++) {
47
48
				if (string.charAt(offset) == IHtmlTagConstants.HTML_ENTITY_CHARACTERS[index]) {
49
50
					buffer.replace(offset, offset + 1, String.valueOf(IHtmlTagConstants.HTML_ENTITY_CODES[index]));
51
					break;
52
				}
53
			}
54
		}
55
		return buffer.toString();
56
	}
57
58
	/** The invocation context */
59
	private final IQuickAssistInvocationContext fContext;
60
61
	/** The length in the document */
62
	private final int fLength;
63
64
	/** The line where to apply the correction */
65
	private final String fLine;
66
67
	/** The offset in the document */
68
	private final int fOffset;
69
70
	/** The relevance of this proposal */
71
	private final int fRelevance;
72
73
	/** The word to complete */
74
	private final String fWord;
75
76
	/**
77
	 * Creates a new word correction proposal.
78
	 *
79
	 * @param word the corrected word
80
	 * @param arguments the problem arguments associated with the spelling problem
81
	 * @param offset the offset in the document where to apply the proposal
82
	 * @param length the lenght in the document to apply the proposal
83
	 * @param context the invocation context for this proposal
84
	 * @param relevance the relevance of this proposal
85
	 */
86
	public WordCorrectionProposal(final String word, final String[] arguments, final int offset, final int length, final IQuickAssistInvocationContext context, final int relevance) {
87
88
		fWord= Character.isUpperCase(arguments[0].charAt(0)) ? Character.toUpperCase(word.charAt(0)) + word.substring(1) : word;
89
90
		fOffset= offset;
91
		fLength= length;
92
		fContext= context;
93
		fRelevance= relevance;
94
95
		final StringBuffer buffer= new StringBuffer(80);
96
97
		buffer.append("...<br>"); //$NON-NLS-1$
98
		buffer.append(getHtmlRepresentation(arguments[1]));
99
		buffer.append("<b>"); //$NON-NLS-1$
100
		buffer.append(getHtmlRepresentation(fWord));
101
		buffer.append("</b>"); //$NON-NLS-1$
102
		buffer.append(getHtmlRepresentation(arguments[2]));
103
		buffer.append("<br>..."); //$NON-NLS-1$
104
105
		fLine= buffer.toString();
106
	}
107
108
	/*
109
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(org.eclipse.jface.text.IDocument)
110
	 */
111
	public final void apply(final IDocument document) {
112
		try {
113
			document.replace(fOffset, fLength, fWord);
114
		} catch (BadLocationException exception) {
115
			// Do nothing
116
		}
117
	}
118
119
	/*
120
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo()
121
	 */
122
	public String getAdditionalProposalInfo() {
123
		return fLine;
124
	}
125
126
	/*
127
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getContextInformation()
128
	 */
129
	public final IContextInformation getContextInformation() {
130
		return null;
131
	}
132
133
	/*
134
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString()
135
	 */
136
	public String getDisplayString() {
137
		return Messages.format(SpellingMessages.Spelling_correct_label, new String[] { fWord });
138
	}
139
140
	/*
141
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage()
142
	 */
143
	public Image getImage() {
144
		return JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_RENAME);
145
	}
146
147
	/*
148
	 * @see org.eclipse.jdt.ui.text.java.IJavaCompletionProposal#getRelevance()
149
	 */
150
	public final int getRelevance() {
151
		return fRelevance;
152
	}
153
154
	/*
155
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getSelection(org.eclipse.jface.text.IDocument)
156
	 */
157
	public final Point getSelection(final IDocument document) {
158
159
		int offset= fContext.getOffset();
160
		int length= fContext.getLength();
161
162
		final int delta= fWord.length() - fLength;
163
		if (offset <= fOffset && offset + length >= fOffset)
164
			length += delta;
165
		else if (offset > fOffset && offset + length > fOffset + fLength) {
166
			offset += delta;
167
			length -= delta;
168
		} else
169
			length += delta;
170
171
		return new Point(offset, length);
172
	}
173
}
(-)src/org/eclipse/ui/texteditor/spelling/correction/WordIgnoreProposal.java (+112 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.texteditor.spelling.correction;
13
14
import org.eclipse.swt.graphics.Image;
15
import org.eclipse.swt.graphics.Point;
16
17
import org.eclipse.jface.text.IDocument;
18
import org.eclipse.jface.text.contentassist.IContextInformation;
19
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
20
import org.eclipse.jface.text.source.ISourceViewer;
21
22
import org.eclipse.ui.internal.texteditor.spelling.Messages;
23
import org.eclipse.ui.internal.texteditor.spelling.SpellingMessages;
24
25
import org.eclipse.ui.texteditor.spelling.SpellingProblem;
26
import org.eclipse.ui.texteditor.spelling.engine.ISpellCheckEngine;
27
import org.eclipse.ui.texteditor.spelling.engine.ISpellChecker;
28
import org.eclipse.ui.texteditor.spelling.engine.SpellCheckEngine;
29
30
/**
31
 * Proposal to ignore the word during the current editing session.
32
 *
33
 * @since 3.0
34
 */
35
public class WordIgnoreProposal implements ISpellingCompletionProposal {
36
37
	/** The invocation context */
38
	private IQuickAssistInvocationContext fContext;
39
40
	/** The word to ignore */
41
	private String fWord;
42
43
	/**
44
	 * Creates a new spell ignore proposal.
45
	 *
46
	 * @param word
47
	 *                   The word to ignore
48
	 * @param context
49
	 *                   The invocation context
50
	 */
51
	public WordIgnoreProposal(final String word, final IQuickAssistInvocationContext context) {
52
		fWord= word;
53
		fContext= context;
54
	}
55
56
	/*
57
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(org.eclipse.jface.text.IDocument)
58
	 */
59
	public final void apply(final IDocument document) {
60
61
		final ISpellCheckEngine engine= SpellCheckEngine.getInstance();
62
		final ISpellChecker checker= engine.getSpellChecker();
63
64
		if (checker != null) {
65
			checker.ignoreWord(fWord);
66
			ISourceViewer sourceViewer= fContext.getSourceViewer();
67
			if (sourceViewer != null)
68
				SpellingProblem.removeAll(sourceViewer, fWord);
69
		}
70
	}
71
72
	/*
73
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo()
74
	 */
75
	public String getAdditionalProposalInfo() {
76
		return Messages.format(SpellingMessages.Spelling_ignore_info, new String[] { WordCorrectionProposal.getHtmlRepresentation(fWord) });
77
	}
78
79
	/*
80
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getContextInformation()
81
	 */
82
	public final IContextInformation getContextInformation() {
83
		return null;
84
	}
85
86
	/*
87
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString()
88
	 */
89
	public String getDisplayString() {
90
		return Messages.format(SpellingMessages.Spelling_ignore_label, new String[] { fWord });
91
	}
92
93
	/*
94
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage()
95
	 */
96
	public Image getImage() {
97
		return JavaPluginImages.get(JavaPluginImages.IMG_OBJS_NLS_NEVER_TRANSLATE);
98
	}
99
	/*
100
	 * @see org.eclipse.jdt.ui.text.java.IJavaCompletionProposal#getRelevance()
101
	 */
102
	public final int getRelevance() {
103
		return Integer.MIN_VALUE + 1;
104
	}
105
106
	/*
107
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getSelection(org.eclipse.jface.text.IDocument)
108
	 */
109
	public final Point getSelection(final IDocument document) {
110
		return new Point(fContext.getOffset(), fContext.getLength());
111
	}
112
}
(-)src/org/eclipse/ui/texteditor/spelling/engine/AbstractSpellDictionary.java (+747 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.texteditor.spelling.engine;
12
13
import java.io.BufferedReader;
14
import java.io.FileNotFoundException;
15
import java.io.IOException;
16
import java.io.InputStream;
17
import java.io.InputStreamReader;
18
import java.io.UnsupportedEncodingException;
19
import java.net.MalformedURLException;
20
import java.net.URL;
21
import java.nio.charset.Charset;
22
import java.nio.charset.CharsetDecoder;
23
import java.nio.charset.CodingErrorAction;
24
import java.nio.charset.MalformedInputException;
25
import java.util.ArrayList;
26
import java.util.Arrays;
27
import java.util.HashMap;
28
import java.util.HashSet;
29
import java.util.Iterator;
30
import java.util.Map;
31
import java.util.Set;
32
33
import org.eclipse.core.runtime.IStatus;
34
import org.eclipse.core.runtime.Status;
35
36
import org.eclipse.core.resources.ResourcesPlugin;
37
38
import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
39
import org.eclipse.ui.internal.texteditor.spelling.Messages;
40
import org.eclipse.ui.internal.texteditor.spelling.SpellingMessages;
41
import org.eclipse.ui.internal.texteditor.spelling.engine.DefaultPhoneticDistanceAlgorithm;
42
import org.eclipse.ui.internal.texteditor.spelling.engine.DefaultPhoneticHashProvider;
43
import org.eclipse.ui.internal.texteditor.spelling.engine.IPhoneticDistanceAlgorithm;
44
import org.eclipse.ui.internal.texteditor.spelling.engine.IPhoneticHashProvider;
45
46
import org.eclipse.ui.texteditor.spelling.PreferenceConstants;
47
import org.eclipse.ui.texteditor.spelling.correction.RankedWordProposal;
48
49
/**
50
 * Partial implementation of a spell dictionary.
51
 *
52
 * @since 3.0
53
 */
54
public abstract class AbstractSpellDictionary implements ISpellDictionary {
55
56
	/**
57
	 * Byte array wrapper
58
	 * @since 3.6
59
	 */
60
	private static class ByteArrayWrapper {
61
62
		private static int hashCode(byte[] array) {
63
			int prime= 31;
64
			if (array == null)
65
				return 0;
66
			int result= 1;
67
			for (int index= 0; index < array.length; index++) {
68
				result= prime * result + array[index];
69
			}
70
			return result;
71
		}
72
73
		private byte[] byteArray;
74
75
		public ByteArrayWrapper(byte[] byteArray) {
76
			this.byteArray= byteArray;
77
		}
78
		public int hashCode() {
79
			final int prime= 31;
80
			int result= 1;
81
			result= prime * result + ByteArrayWrapper.hashCode(byteArray);
82
			return result;
83
		}
84
85
		public boolean equals(Object obj) {
86
			if (this == obj)
87
				return true;
88
			if (obj == null)
89
				return false;
90
			if (!(obj instanceof ByteArrayWrapper))
91
				return false;
92
			ByteArrayWrapper other= (ByteArrayWrapper)obj;
93
			if (!Arrays.equals(byteArray, other.byteArray))
94
				return false;
95
			return true;
96
		}
97
	}
98
99
	
100
	/**
101
	 * Canonical name for UTF-8 encoding
102
	 * @since 3.6
103
	 */
104
	private static final String UTF_8= "UTF-8"; //$NON-NLS-1$
105
106
	/** The bucket capacity */
107
	protected static final int BUCKET_CAPACITY= 4;
108
109
	/** The word buffer capacity */
110
	protected static final int BUFFER_CAPACITY= 32;
111
112
	/** The distance threshold */
113
	protected static final int DISTANCE_THRESHOLD= 160;
114
115
	/**
116
	 * The hash load factor
117
	 * @since 3.6
118
	 */
119
	protected static final float LOAD_FACTOR= 0.85f;
120
121
	/** The phonetic distance algorithm */
122
	private IPhoneticDistanceAlgorithm fDistanceAlgorithm= new DefaultPhoneticDistanceAlgorithm();
123
124
	/** The mapping from phonetic hashes to word lists */
125
	private final Map fHashBuckets= new HashMap(getInitialSize(), LOAD_FACTOR);
126
127
	/** The phonetic hash provider */
128
	private IPhoneticHashProvider fHashProvider= new DefaultPhoneticHashProvider();
129
130
	/** Is the dictionary already loaded? */
131
	private boolean fLoaded= false;
132
	/**
133
	 * Must the dictionary be loaded?
134
	 * @since 3.2
135
	 */
136
	private boolean fMustLoad= true;
137
138
	/**
139
	 * Tells whether to strip non-letters at word boundaries.
140
	 * @since 3.3
141
	 */
142
	boolean fIsStrippingNonLetters= true;
143
144
	/**
145
	 * Returns the initial size of dictionary.
146
	 * 
147
	 * @return The initial size of dictionary.
148
	 * @since 3.6
149
	 */
150
	protected int getInitialSize() {
151
		return 32;
152
	}
153
154
	/**
155
	 * Returns all candidates with the same phonetic hash.
156
	 *
157
	 * @param hash
158
	 *                   The hash to retrieve the candidates of
159
	 * @return Array of candidates for the phonetic hash
160
	 */
161
	protected final Object getCandidates(final String hash) {
162
		ByteArrayWrapper hashBytes;
163
		try {
164
			hashBytes= new ByteArrayWrapper(hash.getBytes(UTF_8));
165
		} catch (UnsupportedEncodingException e) {
166
			TextEditorPlugin.log(e);
167
			return null;
168
		}
169
		return fHashBuckets.get(hashBytes);
170
	}
171
172
	/**
173
	 * Returns all candidates that have a phonetic hash within a bounded
174
	 * distance to the specified word.
175
	 *
176
	 * @param word
177
	 *                   The word to find the nearest matches for
178
	 * @param sentence
179
	 *                   <code>true</code> iff the proposals start a new sentence,
180
	 *                   <code>false</code> otherwise
181
	 * @param hashs
182
	 *                   Array of close hashes to find the matches
183
	 * @return Set of ranked words with bounded distance to the specified word
184
	 */
185
	protected final Set getCandidates(final String word, final boolean sentence, final ArrayList hashs) {
186
187
		int distance= 0;
188
		String hash= null;
189
190
		final StringBuffer buffer= new StringBuffer(BUFFER_CAPACITY);
191
		final HashSet result= new HashSet(BUCKET_CAPACITY * hashs.size());
192
193
		for (int index= 0; index < hashs.size(); index++) {
194
195
			hash= (String)hashs.get(index);
196
197
			final Object candidates= getCandidates(hash);
198
			if (candidates == null)
199
				continue;
200
			else if (candidates instanceof byte[]) {
201
				String candidate;
202
				try {
203
					candidate= new String((byte[])candidates, UTF_8);
204
				} catch (UnsupportedEncodingException e) {
205
					TextEditorPlugin.log(e);
206
					return result;
207
				}
208
				distance= fDistanceAlgorithm.getDistance(word, candidate);
209
				if (distance < DISTANCE_THRESHOLD) {
210
					buffer.setLength(0);
211
					buffer.append(candidate);
212
					if (sentence)
213
						buffer.setCharAt(0, Character.toUpperCase(buffer.charAt(0)));
214
					result.add(new RankedWordProposal(buffer.toString(), -distance));
215
				}
216
				continue;
217
			}
218
219
			final ArrayList candidateList= (ArrayList)candidates;
220
			int candidateSize= Math.min(500, candidateList.size()); // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=195357
221
			for (int offset= 0; offset < candidateSize; offset++) {
222
223
				String candidate;
224
				try {
225
					candidate= new String((byte[])candidateList.get(offset), UTF_8);
226
				} catch (UnsupportedEncodingException e) {
227
					TextEditorPlugin.log(e);
228
					return result;
229
				}
230
				distance= fDistanceAlgorithm.getDistance(word, candidate);
231
232
				if (distance < DISTANCE_THRESHOLD) {
233
234
					buffer.setLength(0);
235
					buffer.append(candidate);
236
237
					if (sentence)
238
						buffer.setCharAt(0, Character.toUpperCase(buffer.charAt(0)));
239
240
					result.add(new RankedWordProposal(buffer.toString(), -distance));
241
				}
242
			}
243
		}
244
		return result;
245
	}
246
247
	/**
248
	 * Returns all approximations that have a phonetic hash with smallest
249
	 * possible distance to the specified word.
250
	 *
251
	 * @param word
252
	 *                   The word to find the nearest matches for
253
	 * @param sentence
254
	 *                   <code>true</code> iff the proposals start a new sentence,
255
	 *                   <code>false</code> otherwise
256
	 * @param result
257
	 *                   Set of ranked words with smallest possible distance to the
258
	 *                   specified word
259
	 */
260
	protected final void getCandidates(final String word, final boolean sentence, final Set result) {
261
262
		int distance= 0;
263
		int minimum= Integer.MAX_VALUE;
264
265
		StringBuffer buffer= new StringBuffer(BUFFER_CAPACITY);
266
267
		final Object candidates= getCandidates(fHashProvider.getHash(word));
268
		if (candidates == null)
269
			return;
270
		else if (candidates instanceof byte[]) {
271
			String candidate;
272
			try {
273
				candidate= new String((byte[])candidates, UTF_8);
274
			} catch (UnsupportedEncodingException e) {
275
				TextEditorPlugin.log(e);
276
				return;
277
			}
278
			distance= fDistanceAlgorithm.getDistance(word, candidate);
279
			buffer.append(candidate);
280
			if (sentence)
281
				buffer.setCharAt(0, Character.toUpperCase(buffer.charAt(0)));
282
			result.add(new RankedWordProposal(buffer.toString(), -distance));
283
			return;
284
		}
285
286
		final ArrayList candidateList= (ArrayList)candidates;
287
		final ArrayList matches= new ArrayList(candidateList.size());
288
289
		for (int index= 0; index < candidateList.size(); index++) {
290
			String candidate;
291
			try {
292
				candidate= new String((byte[])candidateList.get(index), UTF_8);
293
			} catch (UnsupportedEncodingException e) {
294
				TextEditorPlugin.log(e);
295
				return;
296
			}
297
			distance= fDistanceAlgorithm.getDistance(word, candidate);
298
299
			if (distance <= minimum) {
300
301
				if (distance < minimum)
302
					matches.clear();
303
304
				buffer.setLength(0);
305
				buffer.append(candidate);
306
307
				if (sentence)
308
					buffer.setCharAt(0, Character.toUpperCase(buffer.charAt(0)));
309
310
				matches.add(new RankedWordProposal(buffer.toString(), -distance));
311
				minimum= distance;
312
			}
313
		}
314
315
		result.addAll(matches);
316
	}
317
318
	/**
319
	 * Tells whether this dictionary is empty.
320
	 *
321
	 * @return <code>true</code> if this dictionary is empty
322
	 * @since 3.3
323
	 */
324
	protected boolean isEmpty() {
325
		return fHashBuckets.size() == 0;
326
	}
327
328
	/**
329
	 * Returns the used phonetic distance algorithm.
330
	 *
331
	 * @return The phonetic distance algorithm
332
	 */
333
	protected final IPhoneticDistanceAlgorithm getDistanceAlgorithm() {
334
		return fDistanceAlgorithm;
335
	}
336
337
	/**
338
	 * Returns the used phonetic hash provider.
339
	 *
340
	 * @return The phonetic hash provider
341
	 */
342
	protected final IPhoneticHashProvider getHashProvider() {
343
		return fHashProvider;
344
	}
345
346
	/*
347
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary#getProposals(java.lang.String,boolean)
348
	 */
349
	public Set getProposals(final String word, final boolean sentence) {
350
351
		try {
352
353
			if (!fLoaded) {
354
				synchronized (this) {
355
					fLoaded= load(getURL());
356
					if (fLoaded)
357
						compact();
358
				}
359
			}
360
361
		} catch (MalformedURLException exception) {
362
			// Do nothing
363
		}
364
365
		final String hash= fHashProvider.getHash(word);
366
		final char[] mutators= fHashProvider.getMutators();
367
368
		final ArrayList neighborhood= new ArrayList((word.length() + 1) * (mutators.length + 2));
369
		neighborhood.add(hash);
370
371
		final Set candidates= getCandidates(word, sentence, neighborhood);
372
		neighborhood.clear();
373
374
		char previous= 0;
375
		char next= 0;
376
377
		char[] characters= word.toCharArray();
378
		for (int index= 0; index < word.length() - 1; index++) {
379
380
			next= characters[index];
381
			previous= characters[index + 1];
382
383
			characters[index]= previous;
384
			characters[index + 1]= next;
385
386
			neighborhood.add(fHashProvider.getHash(new String(characters)));
387
388
			characters[index]= next;
389
			characters[index + 1]= previous;
390
		}
391
392
		final String sentinel= word + " "; //$NON-NLS-1$
393
394
		characters= sentinel.toCharArray();
395
		int offset= characters.length - 1;
396
397
		while (true) {
398
399
			for (int index= 0; index < mutators.length; index++) {
400
401
				characters[offset]= mutators[index];
402
				neighborhood.add(fHashProvider.getHash(new String(characters)));
403
			}
404
405
			if (offset == 0)
406
				break;
407
408
			characters[offset]= characters[offset - 1];
409
			--offset;
410
		}
411
412
		char mutated= 0;
413
		characters= word.toCharArray();
414
415
		for (int index= 0; index < word.length(); index++) {
416
417
			mutated= characters[index];
418
			for (int mutator= 0; mutator < mutators.length; mutator++) {
419
420
				characters[index]= mutators[mutator];
421
				neighborhood.add(fHashProvider.getHash(new String(characters)));
422
			}
423
			characters[index]= mutated;
424
		}
425
426
		characters= word.toCharArray();
427
		final char[] deleted= new char[characters.length - 1];
428
429
		for (int index= 0; index < deleted.length; index++)
430
			deleted[index]= characters[index];
431
432
		next= characters[characters.length - 1];
433
		offset= deleted.length;
434
435
		while (true) {
436
437
			neighborhood.add(fHashProvider.getHash(new String(characters)));
438
			if (offset == 0)
439
				break;
440
441
			previous= next;
442
			next= deleted[offset - 1];
443
444
			deleted[offset - 1]= previous;
445
			--offset;
446
		}
447
448
		neighborhood.remove(hash);
449
		final Set matches= getCandidates(word, sentence, neighborhood);
450
451
		if (matches.size() == 0 && candidates.size() == 0)
452
			getCandidates(word, sentence, candidates);
453
454
		candidates.addAll(matches);
455
456
		return candidates;
457
	}
458
459
	/**
460
	 * Returns the URL of the dictionary word list.
461
	 *
462
	 * @throws MalformedURLException
463
	 *                    if the URL could not be retrieved
464
	 * @return The URL of the dictionary word list
465
	 */
466
	protected abstract URL getURL() throws MalformedURLException;
467
468
	/**
469
	 * Hashes the word into the dictionary.
470
	 *
471
	 * @param word
472
	 *                   The word to hash in the dictionary
473
	 */
474
	protected final void hashWord(final String word) {
475
476
		final String hash= fHashProvider.getHash(word);
477
		ByteArrayWrapper hashBytes;
478
		byte[] wordBytes;
479
		try {
480
			hashBytes= new ByteArrayWrapper(hash.getBytes(UTF_8));
481
			wordBytes= word.getBytes(UTF_8);
482
		} catch (UnsupportedEncodingException e) {
483
			TextEditorPlugin.log(e);
484
			return;
485
		}
486
487
		Object bucket= fHashBuckets.get(hashBytes);
488
489
		if (bucket == null) {
490
			fHashBuckets.put(hashBytes, wordBytes);
491
		} else if (bucket instanceof ArrayList) {
492
			((ArrayList)bucket).add(wordBytes);
493
		} else {
494
			ArrayList list= new ArrayList(BUCKET_CAPACITY);
495
			list.add(bucket);
496
			list.add(wordBytes);
497
			fHashBuckets.put(hashBytes, list);
498
		}
499
	}
500
501
	/*
502
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary#isCorrect(java.lang.String)
503
	 */
504
	public boolean isCorrect(String word) {
505
		word= stripNonLetters(word);
506
		try {
507
508
			if (!fLoaded) {
509
				synchronized (this) {
510
					fLoaded= load(getURL());
511
					if (fLoaded)
512
						compact();
513
				}
514
			}
515
516
		} catch (MalformedURLException exception) {
517
			// Do nothing
518
		}
519
520
		final Object candidates= getCandidates(fHashProvider.getHash(word));
521
		if (candidates == null)
522
			return false;
523
		else if (candidates instanceof byte[]) {
524
			String candidate;
525
			try {
526
				candidate= new String((byte[])candidates, UTF_8);
527
			} catch (UnsupportedEncodingException e) {
528
				TextEditorPlugin.log(e);
529
				return false;
530
			}
531
			if (candidate.equals(word) || candidate.equals(word.toLowerCase()))
532
				return true;
533
			return false;
534
		}
535
		final ArrayList candidateList= (ArrayList)candidates;
536
		byte[] wordBytes;
537
		byte[] lowercaseWordBytes;
538
		try {
539
			wordBytes= word.getBytes(UTF_8);
540
			lowercaseWordBytes= word.toLowerCase().getBytes(UTF_8);
541
		} catch (UnsupportedEncodingException e) {
542
			TextEditorPlugin.log(e);
543
			return false;
544
		}
545
		for (int index= 0; index < candidateList.size(); index++) {
546
			byte[] candidate= (byte[])candidateList.get(index);
547
			if (Arrays.equals(candidate, wordBytes) || Arrays.equals(candidate, lowercaseWordBytes)) {
548
				return true;
549
			}
550
		}
551
		return false;
552
	}
553
554
	/*
555
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary#setStripNonLetters(boolean)
556
	 * @since 3.3
557
	 */
558
	public void setStripNonLetters(boolean state) {
559
		fIsStrippingNonLetters= state;
560
	}
561
562
	/**
563
	 * Strips non-letter characters from the given word.
564
	 * <p>
565
	 * This will only happen if the corresponding preference is enabled.
566
	 * </p>
567
	 *
568
	 * @param word the word to strip
569
	 * @return the stripped word
570
	 * @since 3.3
571
	 */
572
	protected String stripNonLetters(String word) {
573
		if (!fIsStrippingNonLetters)
574
			return word;
575
576
		int i= 0;
577
		int j= word.length() - 1;
578
		while (i <= j && !Character.isLetter(word.charAt(i)))
579
			i++;
580
		if (i > j)
581
			return ""; //$NON-NLS-1$
582
583
		while (j > i && !Character.isLetter(word.charAt(j)))
584
			j--;
585
586
		return word.substring(i, j+1);
587
	}
588
589
	/*
590
	 * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellDictionary#isLoaded()
591
	 */
592
	public synchronized final boolean isLoaded() {
593
		return fLoaded || fHashBuckets.size() > 0;
594
	}
595
596
	/**
597
	 * Loads a dictionary word list from disk.
598
	 *
599
	 * @param url
600
	 *                   The URL of the word list to load
601
	 * @return <code>true</code> iff the word list could be loaded, <code>false</code>
602
	 *               otherwise
603
	 */
604
	protected synchronized boolean load(final URL url) {
605
		 if (!fMustLoad)
606
			 return fLoaded;
607
608
		if (url != null) {
609
			InputStream stream= null;
610
			int line= 0;
611
			try {
612
				stream= url.openStream();
613
				if (stream != null) {
614
					String word= null;
615
616
					// Setup a reader with a decoder in order to read over malformed input if needed.
617
					CharsetDecoder decoder= Charset.forName(getEncoding()).newDecoder();
618
					decoder.onMalformedInput(CodingErrorAction.REPORT);
619
					decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
620
					final BufferedReader reader= new BufferedReader(new InputStreamReader(stream, decoder));
621
622
					boolean doRead= true;
623
					while (doRead) {
624
						try {
625
							word= reader.readLine();
626
						} catch (MalformedInputException ex) {
627
							// Tell the decoder to replace malformed input in order to read the line.
628
							decoder.onMalformedInput(CodingErrorAction.REPLACE);
629
							decoder.reset();
630
							word= reader.readLine();
631
							decoder.onMalformedInput(CodingErrorAction.REPORT);
632
633
							String message= Messages.format(SpellingMessages.AbstractSpellingDictionary_encodingError,
634
									new String[] { word, decoder.replacement(), BasicElementLabels.getURLPart(url.toString()) });
635
							IStatus status= new Status(IStatus.ERROR, TextEditorPlugin.PLUGIN_ID, IStatus.OK, message, ex);
636
							TextEditorPlugin.log(status);
637
638
							doRead= word != null;
639
							continue;
640
						}
641
						doRead= word != null;
642
						if (doRead)
643
							hashWord(word);
644
					}
645
					return true;
646
				}
647
			} catch (FileNotFoundException ex) {
648
				String urlString= url.toString();
649
				String lowercaseUrlString= urlString.toLowerCase();
650
				if (urlString.equals(lowercaseUrlString))
651
					TextEditorPlugin.log(ex);
652
				else
653
					try {
654
						return load(new URL(lowercaseUrlString));
655
					} catch (MalformedURLException e) {
656
						TextEditorPlugin.log(e);
657
					}
658
			} catch (IOException exception) {
659
				if (line > 0) {
660
					String message= Messages.format(SpellingMessages.AbstractSpellingDictionary_encodingError, new Object[] { new Integer(line), BasicElementLabels.getURLPart(url.toString()) });
661
					IStatus status= new Status(IStatus.ERROR, TextEditorPlugin.PLUGIN_ID, IStatus.OK, message, exception);
662
					TextEditorPlugin.log(status);
663
				} else
664
					TextEditorPlugin.log(exception);
665
			} finally {
666
				fMustLoad= false;
667
				try {
668
					if (stream != null)
669
						stream.close();
670
				} catch (IOException x) {
671
				}
672
			}
673
		}
674
		return false;
675
	}
676
677
	/**
678
	 * Compacts the dictionary.
679
	 *
680
	 * @since 3.3.
681
	 */
682
	private void compact() {
683
		Iterator iter= fHashBuckets.values().iterator();
684
		while (iter.hasNext()) {
685
			Object element= iter.next();
686
			if (element instanceof ArrayList)
687
				((ArrayList)element).trimToSize();
688
		}
689
	}
690
691
	/**
692
	 * Sets the phonetic distance algorithm to use.
693
	 *
694
	 * @param algorithm
695
	 *                   The phonetic distance algorithm
696
	 */
697
	protected final void setDistanceAlgorithm(final IPhoneticDistanceAlgorithm algorithm) {
698
		fDistanceAlgorithm= algorithm;
699
	}
700
701
	/**
702
	 * Sets the phonetic hash provider to use.
703
	 *
704
	 * @param provider
705
	 *                   The phonetic hash provider
706
	 */
707
	protected final void setHashProvider(final IPhoneticHashProvider provider) {
708
		fHashProvider= provider;
709
	}
710
711
	/*
712
	 * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellDictionary#unload()
713
	 */
714
	public synchronized void unload() {
715
		fLoaded= false;
716
		fMustLoad= true;
717
		fHashBuckets.clear();
718
	}
719
720
	/*
721
	 * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellDictionary#acceptsWords()
722
	 */
723
	public boolean acceptsWords() {
724
		return false;
725
	}
726
727
	/*
728
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary#addWord(java.lang.String)
729
	 */
730
	public void addWord(final String word) {
731
		// Do nothing
732
	}
733
734
	/**
735
	 * Returns the encoding of this dictionary.
736
	 *
737
	 * @return the encoding of this dictionary
738
	 * @since 3.3
739
	 */
740
	protected String getEncoding() {
741
		String encoding= TextEditorPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.SPELLING_USER_DICTIONARY_ENCODING);
742
		if (encoding == null || encoding.length() == 0)
743
			encoding= ResourcesPlugin.getEncoding();
744
		return encoding;
745
	}
746
747
}
(-)src/org/eclipse/ui/texteditor/spelling/engine/BasicElementLabels.java (+135 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.texteditor.spelling.engine;
12
13
import java.io.File;
14
15
import org.eclipse.osgi.util.TextProcessor;
16
17
import org.eclipse.core.runtime.IPath;
18
19
import org.eclipse.core.resources.IResource;
20
21
22
/**
23
 * A label provider for basic elements like paths. The label provider will make sure that the labels are correctly
24
 * shown in RTL environments.
25
 *
26
 * @since 3.4
27
 */
28
29
//XXX duplicated from org.eclipse.jdt.internal.junit.BasicElementLabels
30
public class BasicElementLabels {
31
32
	private BasicElementLabels() {
33
	}
34
35
	/**
36
	 * Adds special marks so that that the given string is readable in a BIDI environment.
37
	 * 
38
	 * @param string the string
39
	 * @param delimiters the additional delimiters
40
	 * @return the processed styled string
41
	 */
42
	private static String markLTR(String string, String delimiters) {
43
		return TextProcessor.process(string, delimiters);
44
	}
45
46
	/**
47
	 * Returns the label of a path.
48
	 *
49
	 * @param path the path
50
	 * @param isOSPath if <code>true</code>, the path represents an OS path, if <code>false</code> it is a workspace path.
51
	 * @return the label of the path to be used in the UI.
52
	 */
53
	public static String getPathLabel(IPath path, boolean isOSPath) {
54
		String label;
55
		if (isOSPath) {
56
			label= path.toOSString();
57
		} else {
58
			label= path.makeRelative().toString();
59
		}
60
		return markLTR(label, "/\\:."); //$NON-NLS-1$
61
	}
62
63
	/**
64
	 * Returns the label of the path of a file.
65
	 *
66
	 * @param file the file
67
	 * @return the label of the file path to be used in the UI.
68
	 */
69
	public static String getPathLabel(File file) {
70
		return markLTR(file.getAbsolutePath(), "/\\:."); //$NON-NLS-1$
71
	}
72
73
	/**
74
	 * Returns the label for a file pattern like '*.java'
75
	 *
76
	 * @param name the pattern
77
	 * @return the label of the pattern.
78
	 */
79
	public static String getFilePattern(String name) {
80
		return markLTR(name, "*.?/\\:."); //$NON-NLS-1$
81
	}
82
83
	/**
84
	 * Returns the label for a URL, URI or URL part. Example is 'http://www.x.xom/s.html#1'
85
	 *
86
	 * @param name the URL string
87
	 * @return the label of the URL.
88
	 */
89
	public static String getURLPart(String name) {
90
		return markLTR(name, ":@?-#/\\:."); //$NON-NLS-1$
91
	}
92
93
	/**
94
	 * Returns a label for a resource name.
95
	 *
96
	 * @param resource the resource
97
	 * @return the label of the resource name.
98
	 */
99
	public static String getResourceName(IResource resource) {
100
		return markLTR(resource.getName(), ":."); //$NON-NLS-1$
101
	}
102
103
	/**
104
	 * Returns a label for a resource name.
105
	 *
106
	 * @param resourceName the resource name
107
	 * @return the label of the resource name.
108
	 */
109
	public static String getResourceName(String resourceName) {
110
		return markLTR(resourceName, ":."); //$NON-NLS-1$
111
	}
112
113
	/**
114
	 * Returns a label for a version name. Example is '1.4.1'
115
	 * 
116
	 * @param name the version string
117
	 * @return the version label
118
	 */
119
	public static String getVersionName(String name) {
120
		return markLTR(name, ":."); //$NON-NLS-1$
121
	}
122
123
124
	/**
125
	 * Returns a label for Java element name. Example is 'new Test<? extends List>() { ...}'. This
126
	 * method should only be used for simple element names. Use JavaElementLabels to create a label
127
	 * from a Java element.
128
	 * 
129
	 * @param name the Java element name.
130
	 * @return the label for the Java element
131
	 */
132
	public static String getJavaElementName(String name) {
133
		return markLTR(name, "<>()?,{}.:"); //$NON-NLS-1$
134
	}
135
}
(-)src/org/eclipse/ui/texteditor/spelling/engine/HtmlTagDictionary.java (+66 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.texteditor.spelling.engine;
13
14
import java.net.URL;
15
16
import org.eclipse.ui.texteditor.spelling.correction.IHtmlTagConstants;
17
18
/**
19
 * Dictionary for html tags.
20
 *
21
 * @since 3.0
22
 */
23
public class HtmlTagDictionary extends AbstractSpellDictionary {
24
25
	/*
26
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary#getName()
27
	 */
28
	protected final URL getURL() {
29
		return null;
30
	}
31
32
	/*
33
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary#isCorrect(java.lang.String)
34
	 */
35
	public boolean isCorrect(final String word) {
36
37
		if (word.charAt(0) == IHtmlTagConstants.HTML_TAG_PREFIX)
38
			return super.isCorrect(word);
39
40
		return false;
41
	}
42
43
	/*
44
	 * @see org.eclipse.jdt.ui.text.spelling.engine.AbstractSpellDictionary#load(java.net.URL)
45
	 */
46
	protected synchronized boolean load(final URL url) {
47
48
		unload();
49
50
		for (int index= 0; index < IHtmlTagConstants.HTML_GENERAL_TAGS.length; index++) {
51
52
			hashWord(IHtmlTagConstants.HTML_TAG_PREFIX + IHtmlTagConstants.HTML_GENERAL_TAGS[index] + IHtmlTagConstants.HTML_TAG_POSTFIX);
53
			hashWord(IHtmlTagConstants.HTML_CLOSE_PREFIX + IHtmlTagConstants.HTML_GENERAL_TAGS[index] + IHtmlTagConstants.HTML_TAG_POSTFIX);
54
		}
55
		return true;
56
	}
57
58
	/*
59
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary#stripNonLetters(java.lang.String)
60
	 * @since 3.3
61
	 */
62
	protected String stripNonLetters(String word) {
63
		return word;
64
	}
65
66
}
(-)src/org/eclipse/ui/texteditor/spelling/engine/ISpellCheckEngine.java (+85 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.texteditor.spelling.engine;
13
14
import java.util.Locale;
15
16
import org.eclipse.ui.texteditor.spelling.PreferenceConstants;
17
18
19
/**
20
 * Interface for a spell check engine.
21
 * <p>
22
 * This engine can be configured with multiple
23
 * dictionaries.
24
 * </p>
25
 *
26
 * @since 3.0
27
 */
28
public interface ISpellCheckEngine {
29
30
	/**
31
	 * Returns a spell checker configured with the global
32
	 * dictionaries and the locale dictionary that correspond to the current
33
	 * {@linkplain PreferenceConstants#SPELLING_LOCALE locale preference}.
34
	 * <p>
35
	 * <strong>Note:</strong> Changes to the spelling engine dictionaries
36
	 * are not propagated to this spell checker.</p>
37
	 *
38
	 * @return a configured instance of the spell checker or <code>null</code> if none
39
	 * @throws IllegalStateException if called after being shut down
40
	 */
41
	ISpellChecker getSpellChecker() throws IllegalStateException;
42
43
	/**
44
	 * Returns the locale of the current spell check engine.
45
	 *
46
	 * @return the locale of the current spell check engine
47
	 */
48
	Locale getLocale();
49
50
	/**
51
	 * Registers a global dictionary.
52
	 *
53
	 * @param dictionary the global dictionary to register
54
	 */
55
	void registerGlobalDictionary(ISpellDictionary dictionary);
56
57
	/**
58
	 * Registers a dictionary tuned for the specified locale with this engine.
59
	 *
60
	 * @param locale
61
	 *                   The locale to register the dictionary with
62
	 * @param dictionary
63
	 *                   The dictionary to register
64
	 */
65
	void registerDictionary(Locale locale, ISpellDictionary dictionary);
66
67
	/**
68
	 * Shuts down this spell check engine and its associated components.
69
	 * <p>
70
	 * Further calls to this engine result in exceptions.
71
	 * </p>
72
	 */
73
	void shutdown();
74
75
	/**
76
	 * Unregisters a dictionary previously registered either by a call to
77
	 * <code>registerDictionary(Locale,ISpellDictionary)</code> or <code>registerDictionary(ISpellDictionary)</code>.
78
	 * <p>
79
	 * If the dictionary was not registered before, nothing happens.</p>
80
	 *
81
	 * @param dictionary the dictionary to unregister
82
	 */
83
	void unregisterDictionary(ISpellDictionary dictionary);
84
85
}
(-)src/org/eclipse/ui/texteditor/spelling/engine/ISpellCheckIterator.java (+52 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.texteditor.spelling.engine;
13
14
import java.util.Iterator;
15
16
/**
17
 * Interface for iterators used for spell checking.
18
 *
19
 * @since 3.0
20
 */
21
public interface ISpellCheckIterator extends Iterator {
22
23
	/**
24
	 * Returns the begin index (inclusive) of the current word.
25
	 *
26
	 * @return The begin index of the current word
27
	 */
28
	public int getBegin();
29
30
	/**
31
	 * Returns the end index (exclusive) of the current word.
32
	 *
33
	 * @return The end index of the current word
34
	 */
35
	public int getEnd();
36
37
	/**
38
	 * Does the current word start a new sentence?
39
	 *
40
	 * @return <code>true<code> iff the current word starts a new sentence, <code>false</code> otherwise
41
	 */
42
	public boolean startsSentence();
43
44
	/**
45
	 * Tells whether to ignore single letters
46
	 * from being checked.
47
	 *
48
	 * @since 3.3
49
	 * @param state <code>true</code> if single letters should be ignored
50
	 */
51
	public void setIgnoreSingleLetters(boolean state);
52
}
(-)src/org/eclipse/ui/texteditor/spelling/engine/ISpellChecker.java (+111 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.texteditor.spelling.engine;
13
14
import java.util.Locale;
15
import java.util.Set;
16
17
18
/**
19
 * Interface for spell checkers.
20
 *
21
 * @since 3.0
22
 */
23
public interface ISpellChecker {
24
25
	/**
26
	 * Adds a dictionary to the list of active dictionaries.
27
	 *
28
	 * @param dictionary
29
	 *                   The dictionary to add
30
	 */
31
	void addDictionary(ISpellDictionary dictionary);
32
33
	/**
34
	 * Returns whether this spell checker accepts word additions.
35
	 *
36
	 * @return <code>true</code> if word additions are accepted, <code>false</code> otherwise
37
	 */
38
	boolean acceptsWords();
39
40
	/**
41
	 * Adds the specified word to the set of correct words.
42
	 *
43
	 * @param word
44
	 *                   The word to add to the set of correct words
45
	 */
46
	void addWord(String word);
47
48
	/**
49
	 * Checks the specified word until calling <code>ignoreWord(String)</code>.
50
	 *
51
	 * @param word
52
	 *                   The word to check
53
	 */
54
	void checkWord(String word);
55
56
	/**
57
	 * Checks the spelling with the spell check iterator. Implementations must
58
	 * be thread safe as this may be called inside a reconciler thread.
59
	 *
60
	 * @param listener the spell event listener
61
	 * @param iterator the iterator to use for spell checking
62
	 */
63
	void execute(ISpellEventListener listener, ISpellCheckIterator iterator);
64
65
	/**
66
	 * Returns the ranked proposals for a word.
67
	 *
68
	 * @param word
69
	 *                   The word to retrieve the proposals for
70
	 * @param sentence
71
	 *                   <code>true</code> iff the proposals should start a
72
	 *                   sentence, <code>false</code> otherwise
73
	 * @return Set of ranked proposals for the word
74
	 */
75
	Set getProposals(String word, boolean sentence);
76
77
	/**
78
	 * Ignores the specified word until calling <code>checkWord(String)</code>.
79
	 *
80
	 * @param word
81
	 *                   The word to ignore
82
	 */
83
	void ignoreWord(String word);
84
85
	/**
86
	 * Is the specified word correctly spelled? Implementations must be thread
87
	 * safe as this may be called from within a reconciler thread.
88
	 *
89
	 * @param word
90
	 *                   The word to check its spelling
91
	 * @return <code>true</code> iff the word is correctly spelled, <code>false</code>
92
	 *               otherwise
93
	 */
94
	boolean isCorrect(String word);
95
96
	/**
97
	 * Remove a dictionary from the list of active dictionaries.
98
	 *
99
	 * @param dictionary
100
	 *                   The dictionary to remove
101
	 */
102
	void removeDictionary(ISpellDictionary dictionary);
103
104
	/**
105
	 * Returns the current locale of the spell check engine.
106
	 *
107
	 * @return The current locale of the engine
108
	 * @since 3.3
109
	 */
110
	Locale getLocale();
111
}
(-)src/org/eclipse/ui/texteditor/spelling/engine/ISpellDictionary.java (+77 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.texteditor.spelling.engine;
13
14
import java.util.Set;
15
16
/**
17
 * Interface of dictionaries to use for spell checking.
18
 *
19
 * @since 3.0
20
 */
21
public interface ISpellDictionary {
22
23
	/**
24
	 * Returns whether this dictionary accepts new words.
25
	 *
26
	 * @return <code>true</code> if this dictionary accepts new words, <code>false</code> otherwise
27
	 */
28
	public boolean acceptsWords();
29
30
	/**
31
	 * Externalizes the specified word.
32
	 *
33
	 * @param word
34
	 *                   The word to externalize in the dictionary
35
	 */
36
	public void addWord(String word);
37
38
	/**
39
	 * Returns the ranked word proposals for an incorrectly spelled word.
40
	 *
41
	 * @param word
42
	 *                   The word to retrieve the proposals for
43
	 * @param sentence
44
	 *                   <code>true</code> iff the proposals start a new sentence,
45
	 *                   <code>false</code> otherwise
46
	 * @return Array of ranked word proposals
47
	 */
48
	public Set getProposals(String word, boolean sentence);
49
50
	/**
51
	 * Is the specified word correctly spelled?
52
	 *
53
	 * @param word the word to spell check
54
	 * @return <code>true</code> iff this word is correctly spelled, <code>false</code> otherwise
55
	 */
56
	public boolean isCorrect(String word);
57
58
	/**
59
	 * Is the dictionary loaded?
60
	 *
61
	 * @return <code>true</code> iff it is loaded, <code>false</code> otherwise
62
	 */
63
	public boolean isLoaded();
64
65
	/**
66
	 * Empties the dictionary.
67
	 */
68
	public void unload();
69
70
	/**
71
	 * Tells whether to strip non-letters from word boundaries.
72
	 *
73
	 * @param state <code>true</code> if non-letters should be stripped
74
	 * @since 3.3
75
	 */
76
	public void setStripNonLetters(boolean state);
77
}
(-)src/org/eclipse/ui/texteditor/spelling/engine/ISpellEvent.java (+64 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2007 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.texteditor.spelling.engine;
13
14
import java.util.Set;
15
16
/**
17
 * Event fired by spell checkers.
18
 *
19
 * @since 3.0
20
 */
21
public interface ISpellEvent {
22
23
	/**
24
	 * Returns the begin index of the incorrectly spelled word.
25
	 *
26
	 * @return The begin index of the word
27
	 */
28
	public int getBegin();
29
30
	/**
31
	 * Returns the end index of the incorrectly spelled word.
32
	 *
33
	 * @return The end index of the word
34
	 */
35
	public int getEnd();
36
37
	/**
38
	 * Returns the proposals for the incorrectly spelled word.
39
	 *
40
	 * @return Array of proposals for the word
41
	 */
42
	public Set getProposals();
43
44
	/**
45
	 * Returns the incorrectly spelled word.
46
	 *
47
	 * @return The incorrect word
48
	 */
49
	public String getWord();
50
51
	/**
52
	 * Was the incorrectly spelled word found in the dictionary?
53
	 *
54
	 * @return <code>true</code> iff the word was found, <code>false</code> otherwise
55
	 */
56
	public boolean isMatch();
57
58
	/**
59
	 * Does the incorrectly spelled word start a new sentence?
60
	 *
61
	 * @return <code>true<code> iff the word starts a new sentence, <code>false</code> otherwise
62
	 */
63
	public boolean isStart();
64
}
(-)src/org/eclipse/ui/texteditor/spelling/engine/ISpellEventListener.java (+30 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.texteditor.spelling.engine;
13
14
15
16
/**
17
 * Interface for spell event listeners.
18
 *
19
 * @since 3.0
20
 */
21
public interface ISpellEventListener {
22
23
	/**
24
	 * Handles a spell event.
25
	 *
26
	 * @param event
27
	 *                  Event to handle
28
	 */
29
	public void handle(ISpellEvent event);
30
}
(-)src/org/eclipse/ui/texteditor/spelling/engine/ISpellingEngine.java (+47 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.ui.texteditor.spelling.engine;
13
14
import org.eclipse.core.runtime.IProgressMonitor;
15
16
import org.eclipse.jface.text.IDocument;
17
import org.eclipse.jface.text.IRegion;
18
19
import org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector;
20
import org.eclipse.ui.texteditor.spelling.SpellingContext;
21
22
/**
23
 * A spelling engine that can be contributed to the
24
 * <code>org.eclipse.ui.workbench.texteditor.spellingEngine</code> extension
25
 * point. The <code>SpellingContext</code> provides information about the
26
 * content type to be checked. In general a spelling engine should at least
27
 * support the text {@link org.eclipse.core.runtime.content.IContentType content type}.
28
 * <p>
29
 * This interface is intended to be implemented by clients.
30
 * </p>
31
 *
32
 * @since 3.1
33
 */
34
public interface ISpellingEngine {
35
36
	/**
37
	 * Checks the given regions in the given document. Reports all found
38
	 * spelling problems to the collector.
39
	 *
40
	 * @param document the document to check
41
	 * @param regions the regions to check
42
	 * @param context the context
43
	 * @param collector the problem collector
44
	 * @param monitor the progress monitor, can be <code>null</code>
45
	 */
46
	public void check(IDocument document, IRegion[] regions, SpellingContext context, ISpellingProblemCollector collector, IProgressMonitor monitor);
47
}
(-)src/org/eclipse/ui/texteditor/spelling/engine/JavaDocTagDictionary.java (+71 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.texteditor.spelling.engine;
12
13
import java.net.URL;
14
15
import org.eclipse.ui.texteditor.spelling.correction.IJavaDocTagConstants;
16
17
18
19
/**
20
 * Dictionary for Javadoc tags.
21
 *
22
 * @since 3.0
23
 */
24
public class JavaDocTagDictionary extends AbstractSpellDictionary implements IJavaDocTagConstants {
25
26
	/*
27
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary#getName()
28
	 */
29
	protected final URL getURL() {
30
		return null;
31
	}
32
33
	/*
34
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary#isCorrect(java.lang.String)
35
	 */
36
	public boolean isCorrect(final String word) {
37
38
		if (word.charAt(0) == JAVADOC_TAG_PREFIX)
39
			return super.isCorrect(word);
40
41
		return false;
42
	}
43
44
	/*
45
	 * @see org.eclipse.jdt.ui.text.spelling.engine.AbstractSpellDictionary#load(java.net.URL)
46
	 */
47
	protected synchronized boolean load(final URL url) {
48
49
		unload();
50
51
		for (int index= 0; index < JAVADOC_LINK_TAGS.length; index++)
52
			hashWord(JAVADOC_LINK_TAGS[index]);
53
54
		for (int index= 0; index < JAVADOC_ROOT_TAGS.length; index++)
55
			hashWord(JAVADOC_ROOT_TAGS[index]);
56
57
		for (int index= 0; index < JAVADOC_PARAM_TAGS.length; index++)
58
			hashWord(JAVADOC_PARAM_TAGS[index]);
59
60
		return true;
61
	}
62
63
	/*
64
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.AbstractSpellDictionary#stripNonLetters(java.lang.String)
65
	 * @since 3.3
66
	 */
67
	protected String stripNonLetters(String word) {
68
		return word;
69
	}
70
71
}
(-)src/org/eclipse/ui/texteditor/spelling/engine/SpellCheckEngine.java (+498 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.texteditor.spelling.engine;
12
13
import java.io.File;
14
import java.io.IOException;
15
import java.io.InputStream;
16
import java.net.MalformedURLException;
17
import java.net.URL;
18
import java.util.Collections;
19
import java.util.Enumeration;
20
import java.util.HashMap;
21
import java.util.HashSet;
22
import java.util.Iterator;
23
import java.util.Locale;
24
import java.util.Map;
25
import java.util.Map.Entry;
26
import java.util.Set;
27
28
import org.eclipse.core.runtime.FileLocator;
29
30
import org.eclipse.jface.preference.IPreferenceStore;
31
import org.eclipse.jface.util.IPropertyChangeListener;
32
import org.eclipse.jface.util.PropertyChangeEvent;
33
34
import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
35
import org.eclipse.ui.internal.texteditor.spelling.engine.DefaultSpellChecker;
36
import org.eclipse.ui.internal.texteditor.spelling.engine.LocaleSensitiveSpellDictionary;
37
import org.eclipse.ui.internal.texteditor.spelling.engine.PersistentSpellDictionary;
38
39
import org.eclipse.ui.texteditor.spelling.PreferenceConstants;
40
import org.eclipse.ui.texteditor.spelling.SpellingService;
41
42
43
/**
44
 * Spell check engine for Java source spell checking.
45
 *
46
 * @since 3.0
47
 */
48
public class SpellCheckEngine implements ISpellCheckEngine, IPropertyChangeListener {
49
50
	/** The dictionary location */
51
	public static final String DICTIONARY_LOCATION= "dictionaries/"; //$NON-NLS-1$
52
53
	/** The singleton engine instance */
54
	private static ISpellCheckEngine fgEngine= null;
55
56
	/**
57
	 * Caches the locales of installed dictionaries.
58
	 *
59
	 * @since 3.3
60
	 */
61
	private static Set fgLocalesWithInstalledDictionaries;
62
63
	/**
64
	 * Returns the locales for which this
65
	 * spell check engine has dictionaries in certain location.
66
	 *
67
	 * @param location dictionaries location
68
	 * @return The available locales for this engine
69
	 */
70
	private static Set getLocalesWithInstalledDictionaries(URL location) {
71
		String[] fileNames;
72
		try {
73
			URL url= FileLocator.toFileURL(location);
74
			File file= new File(url.getFile());
75
			if (!file.isDirectory())
76
				return Collections.EMPTY_SET;
77
			fileNames= file.list();
78
			if (fileNames == null)
79
				return Collections.EMPTY_SET;
80
		} catch (IOException ex) {
81
			TextEditorPlugin.log(ex);
82
			return Collections.EMPTY_SET;
83
		}
84
85
		Set localesWithInstalledDictionaries= new HashSet();
86
		int fileNameCount= fileNames.length;
87
		for (int i= 0; i < fileNameCount; i++) {
88
			String fileName= fileNames[i];
89
			int localeEnd= fileName.indexOf(".dictionary"); //$NON-NLS-1$
90
			if (localeEnd > 1) {
91
				String localeName= fileName.substring(0, localeEnd);
92
				int languageEnd=localeName.indexOf('_');
93
				if (languageEnd == -1)
94
					localesWithInstalledDictionaries.add(new Locale(localeName));
95
				else if (languageEnd == 2 && localeName.length() == 5)
96
					localesWithInstalledDictionaries.add(new Locale(localeName.substring(0, 2), localeName.substring(3)));
97
				else if (localeName.length() > 6 && localeName.charAt(5) == '_')
98
					localesWithInstalledDictionaries.add(new Locale(localeName.substring(0, 2), localeName.substring(3, 5), localeName.substring(6)));
99
			}
100
		}
101
102
		return localesWithInstalledDictionaries;
103
	}
104
105
106
	/**
107
	 * Returns the locales for which this
108
	 * spell check engine has dictionaries.
109
	 *
110
	 * @return The available locales for this engine
111
	 */
112
	public static Set getLocalesWithInstalledDictionaries() {
113
		if (fgLocalesWithInstalledDictionaries != null)
114
			return fgLocalesWithInstalledDictionaries;
115
116
		Enumeration locations;
117
		try {
118
			locations= getDictionaryLocations();
119
			if (locations == null)
120
				return fgLocalesWithInstalledDictionaries= Collections.EMPTY_SET;
121
		} catch (IOException ex) {
122
			TextEditorPlugin.log(ex);
123
			return fgLocalesWithInstalledDictionaries= Collections.EMPTY_SET;
124
		}
125
126
		fgLocalesWithInstalledDictionaries= new HashSet();
127
128
		while (locations.hasMoreElements()) {
129
			URL location= (URL) locations.nextElement();
130
			Set locales= getLocalesWithInstalledDictionaries(location);
131
			fgLocalesWithInstalledDictionaries.addAll(locales);
132
		}
133
134
		return fgLocalesWithInstalledDictionaries;
135
	}
136
137
	/**
138
	 * Returns the default locale for this engine.
139
	 *
140
	 * @return The default locale
141
	 */
142
	public static Locale getDefaultLocale() {
143
		return Locale.getDefault();
144
	}
145
146
	/**
147
	 * Returns the dictionary closest to the given locale.
148
	 *
149
	 * @param locale the locale
150
	 * @return the dictionary or <code>null</code> if none is suitable
151
	 * @since 3.3
152
	 */
153
	public ISpellDictionary findDictionary(Locale locale) {
154
		ISpellDictionary dictionary= (ISpellDictionary)fLocaleDictionaries.get(locale);
155
		if (dictionary != null)
156
			return dictionary;
157
158
		// Try same language
159
		String language= locale.getLanguage();
160
		Iterator iter= fLocaleDictionaries.entrySet().iterator();
161
		while (iter.hasNext()) {
162
			Entry entry= (Entry)iter.next();
163
			Locale dictLocale= (Locale)entry.getKey();
164
			if (dictLocale.getLanguage().equals(language))
165
				return (ISpellDictionary)entry.getValue();
166
		}
167
168
		return null;
169
	}
170
171
	/*
172
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine#findDictionary(java.util.Locale)
173
	 * @since 3.3
174
	 */
175
	public static Locale findClosestLocale(Locale locale) {
176
		if (locale == null || locale.toString().length() == 0)
177
			return locale;
178
179
		if (getLocalesWithInstalledDictionaries().contains(locale))
180
			return locale;
181
182
		// Try same language
183
		String language= locale.getLanguage();
184
		Iterator iter= getLocalesWithInstalledDictionaries().iterator();
185
		while (iter.hasNext()) {
186
			Locale dictLocale= (Locale)iter.next();
187
			if (dictLocale.getLanguage().equals(language))
188
				return dictLocale;
189
		}
190
191
		// Try whether American English is present
192
		Locale defaultLocale= Locale.US;
193
		if (getLocalesWithInstalledDictionaries().contains(defaultLocale))
194
			return defaultLocale;
195
196
		return null;
197
	}
198
199
	/**
200
	 * Returns the enumeration of URLs for the dictionary locations where
201
	 * the Platform dictionaries are located.
202
	 * <p>
203
	 * This is in <code>org.eclipse.jdt.ui/dictionaries/</code>
204
	 * which can also be populated via fragments.
205
	 * </p>
206
	 *
207
	 * @throws IOException if there is an I/O error
208
	 * @return The dictionary locations, or <code>null</code> iff the locations are not known
209
	 */
210
	public static Enumeration getDictionaryLocations() throws IOException {
211
		final TextEditorPlugin plugin= TextEditorPlugin.getDefault();
212
		if (plugin != null)
213
			return plugin.getBundle().getResources("/" + DICTIONARY_LOCATION); //$NON-NLS-1$
214
		return null;
215
	}
216
217
	/**
218
	 * Returns the singleton instance of the spell check engine.
219
	 *
220
	 * @return The singleton instance of the spell check engine
221
	 */
222
	public static synchronized final ISpellCheckEngine getInstance() {
223
224
		if (fgEngine == null)
225
			fgEngine= new SpellCheckEngine();
226
227
		return fgEngine;
228
	}
229
230
	/**
231
	 * Shuts down the singleton instance of the spell check engine.
232
	 */
233
	public static synchronized final void shutdownInstance() {
234
		if (fgEngine != null) {
235
			fgEngine.shutdown();
236
			fgEngine= null;
237
		}
238
	}
239
240
	/** The registered locale insensitive dictionaries */
241
	private Set fGlobalDictionaries= new HashSet();
242
243
	/** The spell checker for fLocale */
244
	private ISpellChecker fChecker= null;
245
246
	/** The registered locale sensitive dictionaries */
247
	private Map fLocaleDictionaries= new HashMap();
248
249
	/** The user dictionary */
250
	private ISpellDictionary fUserDictionary= null;
251
252
	/**
253
	 * Creates a new spell check manager.
254
	 */
255
	private SpellCheckEngine() {
256
257
		//TODO : fix this
258
		//fGlobalDictionaries.add(new TaskTagDictionary());
259
		fGlobalDictionaries.add(new HtmlTagDictionary());
260
		fGlobalDictionaries.add(new JavaDocTagDictionary());
261
262
		try {
263
264
			Locale locale= null;
265
			final Enumeration locations= getDictionaryLocations();
266
267
			while (locations != null && locations.hasMoreElements()) {
268
				URL location= (URL)locations.nextElement();
269
270
				for (final Iterator iterator= getLocalesWithInstalledDictionaries(location).iterator(); iterator.hasNext();) {
271
272
					locale= (Locale)iterator.next();
273
					fLocaleDictionaries.put(locale, new LocaleSensitiveSpellDictionary(locale, location));
274
				}
275
			}
276
277
		} catch (IOException exception) {
278
			// Do nothing
279
		}
280
281
		TextEditorPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this);
282
		TextEditorPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this); //TODO : is this good?
283
	}
284
285
	/*
286
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine#getSpellChecker()
287
	 */
288
	public synchronized final ISpellChecker getSpellChecker() throws IllegalStateException {
289
		if (fGlobalDictionaries == null)
290
			throw new IllegalStateException("spell checker has been shut down"); //$NON-NLS-1$
291
292
		IPreferenceStore store= TextEditorPlugin.getDefault().getPreferenceStore();
293
		Locale locale= getCurrentLocale(store);
294
		locale= Locale.US;
295
		//TODO: user dictionary
296
		if (/*fUserDictionary == null &&*/"".equals(locale.toString())) //$NON-NLS-1$
297
			return null;
298
299
		if (fChecker != null && fChecker.getLocale().equals(locale))
300
			return fChecker;
301
302
		resetSpellChecker();
303
304
		fChecker= new DefaultSpellChecker(store, locale);
305
		resetUserDictionary();
306
307
		for (Iterator iterator= fGlobalDictionaries.iterator(); iterator.hasNext();) {
308
			ISpellDictionary dictionary= (ISpellDictionary)iterator.next();
309
			fChecker.addDictionary(dictionary);
310
		}
311
312
		ISpellDictionary dictionary= findDictionary(fChecker.getLocale());
313
		if (dictionary != null)
314
			fChecker.addDictionary(dictionary);
315
316
		return fChecker;
317
	}
318
319
	/**
320
	 * Returns the current locale of the spelling preferences.
321
	 *
322
	 * @param store the preference store
323
	 * @return The current locale of the spelling preferences
324
	 */
325
	private Locale getCurrentLocale(IPreferenceStore store) {
326
		return convertToLocale(store.getString(PreferenceConstants.SPELLING_LOCALE));
327
	}
328
329
	public static Locale convertToLocale(String locale) {
330
		Locale defaultLocale= SpellCheckEngine.getDefaultLocale();
331
		if (locale.equals(defaultLocale.toString()))
332
			return defaultLocale;
333
334
		int length= locale.length();
335
		if (length >= 5)
336
			return new Locale(locale.substring(0, 2), locale.substring(3, 5));
337
338
		if (length == 2 && locale.indexOf('_') == -1)
339
			return new Locale(locale);
340
341
		if (length == 3 && locale.charAt(0) == '_')
342
			return new Locale("", locale.substring(1)); //$NON-NLS-1$
343
344
		return new Locale(""); //$NON-NLS-1$
345
	}
346
347
	/*
348
	 * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellCheckEngine#getLocale()
349
	 */
350
	public synchronized final Locale getLocale() {
351
		if (fChecker == null)
352
			return null;
353
354
		return fChecker.getLocale();
355
	}
356
357
	/*
358
	 * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
359
	 */
360
	public final void propertyChange(final PropertyChangeEvent event) {
361
		if (event.getProperty().equals(PreferenceConstants.SPELLING_LOCALE)) {
362
			resetSpellChecker();
363
			return;
364
		}
365
366
		if (event.getProperty().equals(PreferenceConstants.SPELLING_USER_DICTIONARY)) {
367
			resetUserDictionary();
368
			return;
369
		}
370
371
		if (event.getProperty().equals(PreferenceConstants.SPELLING_USER_DICTIONARY_ENCODING)) {
372
			resetUserDictionary();
373
			return;
374
		}
375
376
		if (event.getProperty().equals(SpellingService.PREFERENCE_SPELLING_ENABLED) && !TextEditorPlugin.getDefault().getPreferenceStore().getBoolean(SpellingService.PREFERENCE_SPELLING_ENABLED)) { //TODO: is this good?
377
			if (this == fgEngine)
378
				SpellCheckEngine.shutdownInstance();
379
			else
380
				shutdown();
381
		}
382
	}
383
384
	/**
385
	 * Resets the current checker's user dictionary.
386
	 */
387
	private synchronized void resetUserDictionary() {
388
		if (fChecker == null)
389
			return;
390
391
		// Update user dictionary
392
		if (fUserDictionary != null) {
393
			fChecker.removeDictionary(fUserDictionary);
394
			fUserDictionary.unload();
395
			fUserDictionary= null;
396
		}
397
398
		IPreferenceStore store= TextEditorPlugin.getDefault().getPreferenceStore();
399
		String filePath= "C:\\workspaces\\jdt\\org.eclipse.jdt.ui.spelling\\en_us.dictionary";
400
			
401
		//TODO: code commented for testing purpose, need to uncomment later
402
		//store.getString(PreferenceConstants.SPELLING_USER_DICTIONARY);
403
404
	/*	VariablesPlugin variablesPlugin= VariablesPlugin.getDefault();
405
		if (variablesPlugin == null)
406
			return;
407
408
		IStringVariableManager variableManager= variablesPlugin.getStringVariableManager();
409
		try {
410
			filePath= variableManager.performStringSubstitution(filePath);
411
		} catch (CoreException e) {
412
			TextEditorPlugin.log(e);
413
			return;
414
		}
415
*/		if (filePath.length() > 0) {
416
			try {
417
				File file= new File(filePath);
418
				if (!file.exists() && !file.createNewFile())
419
					return;
420
421
				final URL url= new URL("file", null, filePath); //$NON-NLS-1$
422
				InputStream stream= url.openStream();
423
				if (stream != null) {
424
					try {
425
						fUserDictionary= new PersistentSpellDictionary(url);
426
						fChecker.addDictionary(fUserDictionary);
427
					} finally {
428
						stream.close();
429
					}
430
				}
431
			} catch (MalformedURLException exception) {
432
				TextEditorPlugin.log(exception);
433
			} catch (IOException exception) {
434
				TextEditorPlugin.log(exception);
435
			}
436
		}
437
	}
438
439
	/*
440
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine#registerDictionary(org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary)
441
	 */
442
	public synchronized final void registerGlobalDictionary(final ISpellDictionary dictionary) {
443
		fGlobalDictionaries.add(dictionary);
444
		resetSpellChecker();
445
	}
446
447
	/*
448
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine#registerDictionary(java.util.Locale, org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellDictionary)
449
	 */
450
	public synchronized final void registerDictionary(final Locale locale, final ISpellDictionary dictionary) {
451
		fLocaleDictionaries.put(locale, dictionary);
452
		resetSpellChecker();
453
	}
454
455
	/*
456
	 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine#unload()
457
	 */
458
	public synchronized final void shutdown() {
459
460
		TextEditorPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this);
461
		TextEditorPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this); // TODO: is this good? and why is the same line twice
462
463
		ISpellDictionary dictionary= null;
464
		for (final Iterator iterator= fGlobalDictionaries.iterator(); iterator.hasNext();) {
465
			dictionary= (ISpellDictionary)iterator.next();
466
			dictionary.unload();
467
		}
468
		fGlobalDictionaries= null;
469
470
		for (final Iterator iterator= fLocaleDictionaries.values().iterator(); iterator.hasNext();) {
471
			dictionary= (ISpellDictionary)iterator.next();
472
			dictionary.unload();
473
		}
474
		fLocaleDictionaries= null;
475
476
		fUserDictionary= null;
477
		fChecker= null;
478
	}
479
480
	private synchronized void resetSpellChecker() {
481
		if (fChecker != null) {
482
			ISpellDictionary dictionary= (ISpellDictionary)fLocaleDictionaries.get(fChecker.getLocale());
483
			if (dictionary != null)
484
				dictionary.unload();
485
		}
486
		fChecker= null;
487
	}
488
489
	/*
490
	 * @see org.eclipse.jdt.ui.text.spelling.engine.ISpellCheckEngine#unregisterDictionary(org.eclipse.jdt.ui.text.spelling.engine.ISpellDictionary)
491
	 */
492
	public synchronized final void unregisterDictionary(final ISpellDictionary dictionary) {
493
		fGlobalDictionaries.remove(dictionary);
494
		fLocaleDictionaries.values().remove(dictionary);
495
		dictionary.unload();
496
		resetSpellChecker();
497
	}
498
}
(-)src/org/eclipse/ui/texteditor/spelling/engine/SpellingEngine.java (+99 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.texteditor.spelling.engine;
12
13
import org.eclipse.core.runtime.IProgressMonitor;
14
15
import org.eclipse.jface.text.IDocument;
16
import org.eclipse.jface.text.IRegion;
17
18
import org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector;
19
import org.eclipse.ui.texteditor.spelling.SpellingContext;
20
import org.eclipse.ui.texteditor.spelling.TextSpellingProblem;
21
22
23
/**
24
 * Internal abstract spelling engine, subclasses provide a content-type specific implementation.
25
 *
26
 * @since 3.1
27
 */
28
public abstract class SpellingEngine implements ISpellingEngine {
29
30
	/**
31
	 * {@link ISpellEvent}listener that forwards events as
32
	 * {@link org.eclipse.ui.texteditor.spelling.SpellingProblem}.
33
	 */
34
	protected static class SpellEventListener implements ISpellEventListener {
35
36
		/** Spelling problem collector */
37
		private ISpellingProblemCollector fCollector;
38
39
		/**
40
		 * The document.
41
		 * @since 3.3
42
		 */
43
		private IDocument fDocument;
44
45
		private int fProblemsThreshold;
46
		private int fProblemCount;
47
48
		/**
49
		 * Initialize with the given spelling problem collector.
50
		 *
51
		 * @param collector the spelling problem collector
52
		 * @param document the document
53
		 */
54
		public SpellEventListener(ISpellingProblemCollector collector, IDocument document) {
55
			fCollector= collector;
56
			fDocument= document;
57
			fProblemsThreshold= 100;//TODO: assigned to 100 for testing, remove later//PreferenceConstants.getPreferenceStore().getInt(PreferenceConstants.SPELLING_PROBLEMS_THRESHOLD);
58
		}
59
60
		/*
61
		 * @see org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEventListener#handle(org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellEvent)
62
		 */
63
		public void handle(ISpellEvent event) {
64
			if (isProblemsThresholdReached())
65
				return;
66
			fProblemCount++;
67
			//fCollector.accept(new JavaSpellingProblem(event, fDocument)); //TODO ???
68
			fCollector.accept(new TextSpellingProblem(event, fDocument));
69
		}
70
71
		public boolean isProblemsThresholdReached() {
72
			return fProblemCount >= fProblemsThreshold;
73
		}
74
	}
75
76
	/*
77
	 * @see org.eclipse.ui.texteditor.spelling.ISpellingEngine#check(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IRegion[], org.eclipse.ui.texteditor.spelling.SpellingContext, org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector, org.eclipse.core.runtime.IProgressMonitor)
78
	 */
79
	public void check(IDocument document, IRegion[] regions, SpellingContext context, ISpellingProblemCollector collector, IProgressMonitor monitor) {
80
		if (collector != null) {
81
			final ISpellCheckEngine spellingEngine= SpellCheckEngine.getInstance();
82
			ISpellChecker checker= spellingEngine.getSpellChecker();
83
			if (checker != null)
84
				check(document, regions, checker, collector, monitor);
85
		}
86
	}
87
88
	/**
89
	 * Spell checks the given document regions with the given arguments.
90
	 *
91
	 * @param document the document
92
	 * @param regions the regions
93
	 * @param checker the spell checker
94
	 * @param collector the spelling problem collector
95
	 * @param monitor the progress monitor, can be <code>null</code>
96
	 */
97
	protected abstract void check(IDocument document, IRegion[] regions, ISpellChecker checker, ISpellingProblemCollector collector, IProgressMonitor monitor);
98
99
}

Return to bug 185695