Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 61 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
61
Dung lượng
751,11 KB
Nội dung
public void run() { currentTarget.setSelection(start, end); } }); } /** * Notification that event processing was finished. */ public synchronized void continueSpellChecking() { // Disable action while busy CheckSpellingActionDelegate action = SpellCheckerPlugin .getSpellCheckingActionDelegate(); action.indicateBusy(true); // Release waiting thread notifyAll(); } Operations The current spell-checking process can be canceled via the abortSpellChecking() method To do so, the method just sets a flag. Then the spellingError() method is awakened once again and simply terminates itself after canceling the spell-checking process by calling the event object’s cancel() method. /** * Cancels the current spell checking process. */ public void abortSpellChecking() { abort = true; continueSpellChecking(); } The replaceWord() method is used to apply the end user’s corrections to the current document. This is done via the spell-checking target’s replaceText() method. This method returns the change in text length caused by the replacement. This value is added to the length of the current selection, so that the selection shrinks and grows with text replacements. All of this logic is encapsulated into a syncExec() call to avoid SWT thread errors (see the section “Displays, Shells, and Monitors” in Chapter 8). /** * Replace word in the current document * * @param pos - Absolute position in the document * @param count - Number of characters to be replaced * @param newWord - The replacement string */ public void replaceWord(final int pos, final int count, final String newWord) { // Execute this via syncExec, // since it originates from the spell checking thread. display.syncExec(new Runnable() { public void run() { 462 Chapter 13 15_020059_ch13.qxd 10/8/04 12:49 PM Page 462 currentSelection.y += currentTarget.replaceText(pos, count, newWord); } }); } } Analyzing Documents The jazzy spell-checking engine uses the tokenizer to break documents into single words. The tokenizer used in this plug-in is loosely based on the original jazzy word tokenizer but was extended with addi- tional functionality and refactored into two classes: ❑ The abstract class AbstractDocumentWordTokenizer serves as a base class for all tokenizer implementations within the spell checker. ❑ The default tokenizer DocumentWordTokenizer is based on this class. This tokenizer is used for plain text files and for all text whose type is unknown. Later, in a further plug-in, I will present another tokenizer class based on AbstractDocumentWordTokenizer. Since these classes are fairly irrelevant in the context of Eclipse plug-in implementation, I refrain from discussing them here. Interested readers can find their source code on this book's Web site (www.wrox.com). See also Appendix C. Configuring the Spell Checker In this section I discuss how preference pages are implemented and how the settings in these preference pages are evaluated. Eclipse already generated the DefaultSpellCheckPreferencePage class dur- ing project setup. Of course, a few changes are necessary to represent the spell-checking options as Eclipse preferences. In addition, the generated class DefaultSpellCheckerPreferencePage has been split into the sep- arate domain model SpellCheckerPreferences and two GUI classes SpellCheckPreferencePage and DefaultSpellCheckerPreferencePage. This offers the advantage that the relatively large GUI classes need not be loaded when the preferences are initialized, thus shortening startup time. Preferences Which options need to be implemented? All the options of the jazzy engine are listed in the configuration.properties file. There are two option groups: the options with the prefix EDIT_ are used for fine-tuning the spell-checking algorithm, while the options with the prefix SPELL_ represent user options. To achieve consistent management for these configuration parameters, I have adopted both 463 Project Three: A Spell Checker as an Eclipse Plug-in 15_020059_ch13.qxd 10/8/04 12:49 PM Page 463 groups into the PreferenceStore (and initialized their default values), but I provide field editors only for the values starting with the prefix SPELL_. I have also introduced a few options by myself: the dictionary path (SPELL_DICTIONARY), the suffix for the user dictionary (USER_DICTIONARY), and the options IGNOREONELETTERWORDS and COMPOUNDCHARACTERS. The default value for the dictionary path is the default dictionary defined in the SpellCheckerPlugin class. Domain Model All options are combined in class SpellCheckerPreferences (Listing 13.4) which implements the preference’s domain model. The GUI part (the Preference Pages) will be implemented in a separate class. This concept will lead to shorter start-up times, since only the domain model needs to be initialized when the plug-in becomes active. The getPluginPreferences() method is used to load the whole set of plug-in–specific preferences. Note that each plug-in has its own set of preferences. This allows the end user to configure the spell checker individually for each file type. For example, Java source files may have a different spell-checking configuration than plain text files. package com.bdaum.SpellChecker.preferences; import org.eclipse.core.runtime.Preferences; import org.eclipse.jface.preference.IPreferenceStore; import com.bdaum.SpellChecker.SpellCheckerPlugin; import com.swabunga.spell.engine.Configuration; public class SpellCheckerPreferences { // Key for dictionary path public static final String SPELL_DICTIONARY = "SPELL_DICTIONARY"; // Key for user dictionary suffix public static final String USER_DICTIONARY = "USER_DICTIONARY"; // Key for option to ignore one letter words public static final String IGNOREONELETTERWORDS = "ignoreOneLetterWords"; // Key for characters in compound words public static final String COMPOUNDCHARACTERS = "compoundCharacters"; /** * Sets the defaults for all preferences * * @param store - the PreferenceStore instance */ public void initializeDefaults(IPreferenceStore store) { // Only initialize if not already initialized // Otherwise preference.ini and plugin_customization.ini // would not work. if (store.getDefaultString(SPELL_DICTIONARY).length() == 0) { initializePublicPreferences(store); 464 Chapter 13 Listing 13.4 (Continues) 15_020059_ch13.qxd 10/8/04 12:49 PM Page 464 initializeHiddenPreferences(store); } } /** * Public configuration data for spell check algorithm * * @param store - the PreferenceStore instance */ protected void initializePublicPreferences(IPreferenceStore store) { store.setDefault(SPELL_DICTIONARY, SpellCheckerPlugin.getDefaultDictionaryFileName()); store.setDefault(Configuration.SPELL_THRESHOLD, 140); store.setDefault(Configuration.SPELL_IGNOREDIGITWORDS, true); store.setDefault(Configuration.SPELL_IGNOREINTERNETADDRESSES, false); store.setDefault(Configuration.SPELL_IGNOREMIXEDCASE, false); store.setDefault(Configuration.SPELL_IGNOREMULTIPLEWORDS, false); store.setDefault(Configuration.SPELL_IGNORESENTENCECAPITALIZATION, false); store.setDefault(Configuration.SPELL_IGNOREUPPERCASE, false); store.setDefault(IGNOREONELETTERWORDS, false); store.setDefault(COMPOUNDCHARACTERS, ".:/@\\"); } /** * Non-public configuration data for spell check algorithm * * @param store - the PreferenceStore instance */ protected void initializeHiddenPreferences(IPreferenceStore store) { store.setDefault(Configuration.COST_REMOVE_CHAR, 95); store.setDefault(Configuration.COST_INSERT_CHAR, 95); store.setDefault(Configuration.COST_SWAP_CHARS, 90); store.setDefault(Configuration.COST_SUBST_CHARS, 100); store.setDefault(Configuration.COST_CHANGE_CASE, 10); } /** * Retrieve plug-in specific preferences * * @return Preferences */ public Preferences getPluginPreferences() { return SpellCheckerPlugin.getDefault().getPluginPreferences(); } } Listing 13.4 (Continued) 465 Project Three: A Spell Checker as an Eclipse Plug-in 15_020059_ch13.qxd 10/8/04 12:49 PM Page 465 The GUI The GUI part of the spell checker preferences consists of an abstract class SpellCheckerPreferencePage which can be utilized by all later add-ons to the spell checker. The class DefaultSpellCheckerPreferencePage extends this class and implements the basic options for operating the spell checker. With class ShortIntegerFieldEditor I show how field editors for preference pages can be extended and modified. The SpellCheckerPreferencePage Class The implementation of the SpellCheckerPreferencePage class closely follows the pregenerated pattern. The generated class DefaultSpellCheckerPreferencePage is renamed to SpellCheckerPreferencePage and completed, while a new version of DefaultSpellCheckerPreferencePage will be created from scratch as a subclass of SpellCheckerPreferencePage. package com.bdaum.SpellChecker.preferences; import org.eclipse.jface.preference.*; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPreferencePage; import org.eclipse.ui.help.WorkbenchHelp; import com.bdaum.SpellChecker.Messages; import com.swabunga.spell.engine.Configuration; /** * This class implements the common parts of spell checker preference * pages. */ public abstract class SpellCheckerPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { Because only letters or digits are allowed in the user dictionary suffix, a special field editor is needed to allow strings containing letters and digits. This is achieved by subclassing the StringFieldEditor class and overriding the doCheckState() method. In addition, the text length is restricted to 15 characters. /** * Subclass of StringFieldEditor in order to check the user * dictionary suffix for invalid characters */ public class UserSuffixFieldEditor extends StringFieldEditor { public UserSuffixFieldEditor(String name, String labelText, Composite parent) { super(name, labelText, 15, parent); } 466 Chapter 13 15_020059_ch13.qxd 10/8/04 12:49 PM Page 466 /** * Checks if entered values are valid * * @return - true if valid */ protected boolean doCheckState() { String txt = getTextControl().getText(); for (int i = 0; i < txt.length(); i++) { if (!Character.isLetterOrDigit(txt.charAt(i))) { setErrorMessage(Messages.getString( "SpellCheckerPreferencePage.Invalid_character_in_suffix")); return false; } } return super.doCheckState(); } } The constructor specifies a grid layout. The init() method just adds a descriptive text to the preference page. I have also extended the createControl() method to set help identification for context-sensitive help (InfoPops). public static final String SPELLCHECKERPREFERENCESCONTEXT = "com.bdaum.SpellChecker.preferences_context"; /* Constructor */ public SpellCheckerPreferencePage() { super(GRID); } /** * Initialization */ public void init(IWorkbench workbench) { setDescription(Messages.getString( "SpellCheckerPreferencePage.All_changes_will_take_effect")); } /** * Get Plug-in specific workspace PreferenceStore instance * * @return - preference store instance */ public abstract IPreferenceStore doGetPreferenceStore(); /** * Construct page content */ public void createControl(Composite parent) { super.createControl(parent); WorkbenchHelp.setHelp(parent.getParent(), getPreferenceHelpContextID()); 467 Project Three: A Spell Checker as an Eclipse Plug-in 15_020059_ch13.qxd 10/8/04 12:49 PM Page 467 } /** * Get Help context id for this preference page * * @return String - the ID for context sensitive help. */ protected String getPreferenceHelpContextID() { return SPELLCHECKERPREFERENCESCONTEXT; } A field editor for each (public) spell-checking option is constructed in the createFieldEditors() method. Because I did not like the long and unlimited fields produced by the IntegerFieldEditor class, I implemented the ShortIntegerFieldEditor class with a configurable number of digits (see the following code). /** * Create field editors */ public void createFieldEditors() { Composite composite = getFieldEditorParent(); addField(new FileFieldEditor( SpellCheckerPreferences.SPELL_DICTIONARY, Messages.getString( "SpellCheckerPreferencePage.Spell_Dictionary_File"), composite)); addField(new UserSuffixFieldEditor( SpellCheckerPreferences.USER_DICTIONARY, Messages.getString( "SpellCheckerPreferencePage.User_Dictionary_File_Suffix"), composite)); ShortIntegerFieldEditor thresholdEditor = new ShortIntegerFieldEditor(Configuration.SPELL_THRESHOLD, Messages.getString( "SpellCheckerPreferencePage.Spell_Threshold"), composite, 4); thresholdEditor.setValidRange(0, 9999); addField(thresholdEditor); addField(new BooleanFieldEditor( Configuration.SPELL_IGNOREDIGITWORDS, Messages.getString( "SpellCheckerPreferencePage.Ignore_Numbers"), composite)); addField(new BooleanFieldEditor( SpellCheckerPreferences.IGNOREONELETTERWORDS, Messages.getString( "SpellCheckerPreferencePage.Ignore_one_letter_words"), composite)); addField(new BooleanFieldEditor( Configuration.SPELL_IGNOREMIXEDCASE, Messages.getString( 468 Chapter 13 15_020059_ch13.qxd 10/8/04 12:49 PM Page 468 "SpellCheckerPreferencePage.Ignore_Mixed_Case"), composite)); addField(new BooleanFieldEditor( Configuration.SPELL_IGNORESENTENCECAPITALIZATION, Messages.getString( "SpellCheckerPreferencePage.Ignore_Sentence_Capitalization"), composite)); addField(new BooleanFieldEditor( Configuration.SPELL_IGNOREUPPERCASE, Messages.getString( "SpellCheckerPreferencePage.Ignore_Upper_Case"), composite)); addField(new StringFieldEditor( SpellCheckerPreferences.COMPOUNDCHARACTERS, Messages.getString( "SpellCheckerPreferencePage.CompoundCharacters"), 15, composite)); } } The DefaultSpellCheckerPreferencePage Class The class DefaultSpellCheckerPreferencePage is very simple (see Listing 13.5). As a subclass of SpellCheckerPreferencePage it implements only the abstract method doGetPreferenceStore(). This method simply fetches the plug-in’s preferences store and returns it. package com.bdaum.SpellChecker.preferences; import org.eclipse.jface.preference.IPreferenceStore; import com.bdaum.SpellChecker.SpellCheckerPlugin; /** * This class implements the preference page for the basic spell * checker options. */ public class DefaultSpellCheckerPreferencePage extends SpellCheckerPreferencePage { /** * Returns the preference store of the default preferences * * @return - the default preference store */ public IPreferenceStore doGetPreferenceStore() { return SpellCheckerPlugin.getDefault().getPreferenceStore(); } } Listing 13.5 469 Project Three: A Spell Checker as an Eclipse Plug-in 15_020059_ch13.qxd 10/8/04 12:49 PM Page 469 The ShortIntegerFieldEditor Class The ShortIntegerFieldEditor class (Listing 13.6) is based on the standard field editor StringFieldEditor. In addition, it sets the number of allowed characters to the specified width and checks the input for nonnumeric characters and for violation of the specified limits. package com.bdaum.SpellChecker.preferences; import org.eclipse.jface.preference.StringFieldEditor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Text; public class ShortIntegerFieldEditor extends StringFieldEditor { private int minValidValue = 0; private int maxValidValue = Integer.MAX_VALUE; /** * Default constructor. */ public ShortIntegerFieldEditor() { super(); } /** * Qualified constructor. * * @param name - preference key * @param labelText - label text string * @param parent - parent composite * @param textLimit - maximum text width */ public ShortIntegerFieldEditor(String name, String labelText, Composite parent, int width) { super(name, labelText, width, parent); setTextLimit(width); setEmptyStringAllowed(false); setErrorMessage(JFaceResources .getString("IntegerFieldEditor.errorMessage")); } /** * Sets the range of valid values for this field. * * @param min - he minimum allowed value (inclusive) * @param max - the maximum allowed value (inclusive) */ public void setValidRange(int min, int max) { minValidValue = min; maxValidValue = max; } /** 470 Chapter 13 Listing 13.6 (Continues) 15_020059_ch13.qxd 10/8/04 12:49 PM Page 470 * Checks for valid field content * * @return - true if valid */ protected boolean checkState() { Text text = getTextControl(); if (text == null) return false; String numberString = text.getText(); try { int number = Integer.valueOf(numberString).intValue(); if (number >= minValidValue && number <= maxValidValue) { clearErrorMessage(); return true; } } catch (NumberFormatException e1) { } showErrorMessage(); return false; } } Listing 13.6 (Continued) Reading from the PreferenceStore What is needed now is a method to pass the options set in the preferences pages to the spell-checking engine. In the SpellCheckerPlugin class (see the section “The Plugin Class”) the jazzy engine was already told to fetch its configuration parameters from the SpellCheckConfiguration class (by set- ting the system property jazzy). Passing the preference values is quite simple. The SpellCheckConfiguration class (Listing 13.7) extends the jazzy class Configuration and overrides the methods getBoolean(), setBoolean(), getInteger(), and setInteger(). In addition, the getString() method was added to be able to fetch the dictionary path and the user dictionary suffix. When a get…() method is invoked, the value belonging to the specified key is fetched from the plug-in preferences. Which plug-in preferences are selected is determined by the SpellCheckManager depending on the type of file to be checked. The set…() methods do nothing, because all preferences are modified via the PreferencePages and not via the Configuration class. package com.bdaum.SpellChecker; import org.eclipse.core.runtime.Preferences; import com.bdaum.SpellChecker.preferences.SpellCheckerPreferences; import com.swabunga.spell.engine.Configuration; public class SpellCheckConfiguration extends Configuration { private static final String TRUE = "true"; 471 Project Three: A Spell Checker as an Eclipse Plug-in Listing 13.7 (Continues) 15_020059_ch13.qxd 10/8/04 12:49 PM Page 471 [...]... help pages is left to your imagination 4 89 Chapter 13 Java- Properties To create a foreign language fragment for the Java- Properties plug-in, just repeat the above steps Create a new fragment project with the project name com.bdaum.SpellChecker.JavaProperties for the plug-in com.bdaum.SpellChecker.JavaProperties, and then create the package com.bdaum.SpellChecker.JavaProperties.de and German-language versions... about.html Additional information for the functions Help > About Eclipse Platform > Feature Details and Help > About Eclipse Platform > Plug-in Details can be provided by adding about.html files to the feature project Spell Checker for Eclipse and the plug-in projects com.bdaum.SpellChecker and com.bdaum.SpellChecker.JavaProperties Such a file can contain references to license information, as shown here:... icons/,\ plugin.properties,\ plugin.xml,\ schema/,\ src/,\ toc.xml Listing 13. 19 4 93 Chapter 13 Figure 13. 5 For the plug-in project com.bdaum.SpellChecker.JavaProperties, proceed as follows: ❑ For the Binary Build, mark the following files and folders: about.html, bin, contexts.xml, html, plugin.properties, plugin.xml, toc.xml ❑ For the Source Build, mark the following files and folders: about.html, contexts.xml,... like Listing 13. 20 bin.includes = plugin.xml,\ JavaPropertiesTokenizer.jar,\ about.html,\ bin/,\ contexts.xml,\ toc.xml source.JavaPropertiesTokenizer.jar = src/ output.JavaPropertiesTokenizer.jar = bin/ src.includes = about.html,\ contexts.xml,\ plugin.xml,\ src/,\ toc.xml Listing 13. 20 494 Project Three: A Spell Checker as an Eclipse Plug-in For the feature project Spell Checker for Eclipse, proceed... contexts.xml file defines only a single new context (for the Java- Properties preference page): 4 83 Chapter 13 Help for Spell Checker JavaProperties Preferences Internationalizing... plugin.properties file in this plug-in is Java_ Properties =Java- Properties Creating a Language Fragment The best way to add foreign language support for a given plug-in is to create a fragment For the spell checker, you will need to create foreign language fragments for both plug-ins: the basic spell checker and the Java- Properties plug-in Fragment Project To create foreign language fragments, invoke the... point="org .eclipse. ui.preferencePages"> Listing 13. 10 (Continues) 4 79 Chapter 13 ... id="com.bdaum.SpellChecker.documentTokenizer" name= "Java- Properties Spell Checker" point="com.bdaum.SpellChecker.documentTokenizer"> ... Java- Properties spell checker add-on < ?eclipse version= "3. 0"?> . SpellCheckerPlugin.getDefault().getPreferenceStore(); } } Listing 13. 5 4 69 Project Three: A Spell Checker as an Eclipse Plug-in 15_0200 59_ ch 13. qxd 10/8/04 12: 49 PM Page 4 69 The ShortIntegerFieldEditor Class The ShortIntegerFieldEditor class (Listing 13. 6). The contexts.xml file is shown in Listing 13. 9. 4 73 Project Three: A Spell Checker as an Eclipse Plug-in 15_0200 59_ ch 13. qxd 10/8/04 12: 49 PM Page 4 73 <?xml version="1.0" encoding="UTF-8"?> <contexts>. file="toc.xml"> </toc> 4 79 Project Three: A Spell Checker as an Eclipse Plug-in Listing 13. 10 (Continues) 15_0200 59_ ch 13. qxd 10/8/04 12: 49 PM Page 4 79 </extension> <extension point="org .eclipse. help.contexts"> <contexts