Omaha #4781: Make improvements to spell checker.
Change-Id: I8e5c951166308ae06f0371711144ee12f8ec8b17 Former-commit-id: f473c8ba23b01cdb43be88bedb6c5bf83c2a196b
This commit is contained in:
parent
c94adfbac9
commit
c2ec09be70
6 changed files with 361 additions and 179 deletions
|
@ -20,9 +20,10 @@
|
|||
package com.raytheon.uf.viz.spellchecker.dialogs;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
|
@ -64,11 +65,11 @@ import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel
|
|||
import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType;
|
||||
import com.raytheon.uf.common.localization.LocalizationFile;
|
||||
import com.raytheon.uf.common.localization.PathManagerFactory;
|
||||
import com.raytheon.uf.common.localization.SaveableOutputStream;
|
||||
import com.raytheon.uf.common.localization.exception.LocalizationException;
|
||||
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||
import com.raytheon.uf.common.status.UFStatus;
|
||||
import com.raytheon.uf.common.status.UFStatus.Priority;
|
||||
import com.raytheon.uf.common.util.FileUtil;
|
||||
import com.raytheon.uf.viz.spellchecker.jobs.SpellCheckJob;
|
||||
|
||||
/**
|
||||
|
@ -84,6 +85,9 @@ import com.raytheon.uf.viz.spellchecker.jobs.SpellCheckJob;
|
|||
* 10/23/2014 #3685 randerso Changes to support mixed case
|
||||
* 10/30/2014 #16693 lshi Add more swear words to the filter
|
||||
* 03/30/2015 #4344 dgilling Make bad word filter configurable.
|
||||
* 08/31/2015 #4781 dgilling Improve handling of proper nouns in all
|
||||
* caps mode, move override dictionary to
|
||||
* SITE level.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -96,78 +100,13 @@ public class SpellCheckDlg extends Dialog implements ISpellingProblemCollector {
|
|||
private static final transient IUFStatusHandler statusHandler = UFStatus
|
||||
.getHandler(SpellCheckDlg.class);
|
||||
|
||||
private static final Pattern DIGITS = Pattern.compile("\\d");
|
||||
private static final String SPELLCHECKER = "spellchecker";
|
||||
|
||||
private static final String SUGGESTION_BLACKLIST_PATH = FileUtil.join(
|
||||
"spellchecker", "inappropriateWords.txt");
|
||||
private static final String SUGGESTION_BLACKLIST_PATH = SPELLCHECKER
|
||||
+ IPathManager.SEPARATOR + "inappropriateWords.txt";
|
||||
|
||||
private static final Pattern COMMENT = Pattern.compile("^#");
|
||||
|
||||
/**
|
||||
* The event handler for the check word button. It doubles as the problem
|
||||
* collector for its internal SpellCheckJob.
|
||||
*
|
||||
* @author wldougher
|
||||
*/
|
||||
class CheckWord extends SelectionAdapter implements
|
||||
ISpellingProblemCollector {
|
||||
|
||||
private SpellCheckJob wordCheckJob;
|
||||
|
||||
private SpellingProblem wordProblem;
|
||||
|
||||
/*
|
||||
* If there's a spelling problem with the replacement word, save the
|
||||
* fact that it was wrong and jump to the end.
|
||||
*
|
||||
* @see
|
||||
* org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#accept
|
||||
* (org.eclipse.ui.texteditor.spelling.SpellingProblem)
|
||||
*/
|
||||
@Override
|
||||
public void accept(SpellingProblem problem) {
|
||||
wordProblem = problem;
|
||||
endCollecting();
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* @seeorg.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#
|
||||
* beginCollecting()
|
||||
*/
|
||||
@Override
|
||||
public void beginCollecting() {
|
||||
wordProblem = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the user if the replacement word is spelled correctly or not.
|
||||
*
|
||||
* @seeorg.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#
|
||||
* endCollecting
|
||||
* ()
|
||||
*/
|
||||
@Override
|
||||
public void endCollecting() {
|
||||
if (wordProblem == null) {
|
||||
wordCheckLbl.setText("The word is correct");
|
||||
} else {
|
||||
wordCheckLbl.setText(wordProblem.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The action taken when the check word button is clicked.
|
||||
*/
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent evt) {
|
||||
wordCheckJob = new SpellCheckJob("wordCheck");
|
||||
wordCheckJob.setCollector(this);
|
||||
wordCheckJob.setText(replaceWithTF.getText());
|
||||
wordCheckJob.schedule();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A pattern to recognize "add to dictionary" proposals
|
||||
*/
|
||||
|
@ -189,9 +128,10 @@ public class SpellCheckDlg extends Dialog implements ISpellingProblemCollector {
|
|||
.getSystemColor(SWT.COLOR_RED));
|
||||
|
||||
/**
|
||||
* The simple name of the user spelling dictionary file
|
||||
* The path to the site level spelling dictionary file
|
||||
*/
|
||||
private static final String SPELLDICT = "spelldict";
|
||||
private static final String SPELLDICT = SPELLCHECKER
|
||||
+ IPathManager.SEPARATOR + "spelldict.txt";
|
||||
|
||||
private Button addWordBtn;
|
||||
|
||||
|
@ -260,7 +200,7 @@ public class SpellCheckDlg extends Dialog implements ISpellingProblemCollector {
|
|||
|
||||
private boolean userDEncodingWasDefault;
|
||||
|
||||
private LocalizationFile userDLFile;
|
||||
private LocalizationFile siteDictionary;
|
||||
|
||||
private String userDToRestore;
|
||||
|
||||
|
@ -268,10 +208,6 @@ public class SpellCheckDlg extends Dialog implements ISpellingProblemCollector {
|
|||
|
||||
private Label wordCheckLbl;
|
||||
|
||||
private String category = "WORKSTATION";
|
||||
|
||||
private String source = "SPELL_CHECKER";
|
||||
|
||||
private boolean sentenceWasDefault;
|
||||
|
||||
private boolean sentenceToRestore;
|
||||
|
@ -290,39 +226,24 @@ public class SpellCheckDlg extends Dialog implements ISpellingProblemCollector {
|
|||
|
||||
private Collection<String> suggestionsBlacklist;
|
||||
|
||||
private final boolean isMixedCase;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param parent
|
||||
* Parent shell.
|
||||
* @param styledTest
|
||||
* control containing the text to spell check
|
||||
*/
|
||||
public SpellCheckDlg(Shell parent, StyledText styledText) {
|
||||
super(parent, SWT.NONE);
|
||||
this.styledText = styledText;
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor. This version allows the client to pass in the category and
|
||||
* source used for message posting.
|
||||
*
|
||||
* @param parent
|
||||
* the parent shell
|
||||
* @param styledText
|
||||
* control containing the text to spell check
|
||||
* @param category
|
||||
* Alert VIZ category
|
||||
* @param source
|
||||
* Alert VIZ source
|
||||
* @param isMixedCase
|
||||
* whether or not this product is in mixed case mode.
|
||||
*/
|
||||
public SpellCheckDlg(Shell parent, StyledText styledText, String category,
|
||||
String source) {
|
||||
public SpellCheckDlg(Shell parent, StyledText styledText,
|
||||
boolean isMixedCase) {
|
||||
super(parent, SWT.NONE);
|
||||
this.styledText = styledText;
|
||||
this.category = category;
|
||||
this.source = source;
|
||||
this.isMixedCase = isMixedCase;
|
||||
this.siteDictionary = getAdditionalDictionary();
|
||||
init();
|
||||
}
|
||||
|
||||
|
@ -402,14 +323,28 @@ public class SpellCheckDlg extends Dialog implements ISpellingProblemCollector {
|
|||
return;
|
||||
}
|
||||
|
||||
/* skip any locked text ranges */
|
||||
StyleRange styleRange = styledText.getStyleRangeAtOffset(problem
|
||||
.getOffset());
|
||||
if ((styleRange != null) && (!styleRange.isUnstyled())
|
||||
&& (!styleRange.similarTo(REDSTYLE))) {
|
||||
scanForErrors();
|
||||
return;
|
||||
}
|
||||
|
||||
/* skip any word we set to ignore */
|
||||
styledText.setSelectionRange(problem.getOffset(), problem.getLength());
|
||||
String badWord = styledText.getSelectionText();
|
||||
if (ignoreAll.contains(badWord)) {
|
||||
scanForErrors();
|
||||
return;
|
||||
}
|
||||
|
||||
this.problem = problem;
|
||||
addWordProposal = null;
|
||||
|
||||
styledText.setSelectionRange(problem.getOffset(), problem.getLength());
|
||||
styledText.showSelection();
|
||||
String badWord = styledText.getSelectionText();
|
||||
misspelledLbl.setText(badWord);
|
||||
|
||||
java.util.List<String> suggestions = new ArrayList<>();
|
||||
boolean foundProperNoun = false;
|
||||
ICompletionProposal[] proposals = problem.getProposals();
|
||||
if ((proposals != null) && (proposals.length > 0)) {
|
||||
for (ICompletionProposal proposal : proposals) {
|
||||
|
@ -417,9 +352,22 @@ public class SpellCheckDlg extends Dialog implements ISpellingProblemCollector {
|
|||
Matcher pdMatch = CHANGE_TO.matcher(pdString);
|
||||
if (pdMatch.matches()) {
|
||||
String replString = pdMatch.group(1);
|
||||
|
||||
/*
|
||||
* To prevent improperly flagging proper nouns in all caps
|
||||
* mode, we'll assume that if the spell checker suggests the
|
||||
* same spelling but a different case that the word is
|
||||
* correct and scan ahead for the next spelling mistake.
|
||||
*/
|
||||
if ((!isMixedCase)
|
||||
&& (badWord.equalsIgnoreCase(replString))) {
|
||||
foundProperNoun = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!suggestionsBlacklist
|
||||
.contains(replString.toUpperCase())) {
|
||||
suggestionList.add(replString);
|
||||
suggestions.add(replString);
|
||||
}
|
||||
}
|
||||
Matcher addMatch = ADD_TO.matcher(pdString);
|
||||
|
@ -427,42 +375,33 @@ public class SpellCheckDlg extends Dialog implements ISpellingProblemCollector {
|
|||
addWordProposal = proposal;
|
||||
}
|
||||
}
|
||||
if (suggestionList.getItemCount() > 0) {
|
||||
suggestionList.select(0);
|
||||
replaceWithTF.setText(suggestionList.getItem(0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
StyleRange styleRange = styledText.getStyleRangeAtOffset(problem
|
||||
.getOffset());
|
||||
if ((styleRange == null) || styleRange.isUnstyled()
|
||||
|| styleRange.similarTo(REDSTYLE)) {
|
||||
if (ignoreAll.contains(badWord)) {
|
||||
scanForErrors();
|
||||
} else {
|
||||
replaceBtn.setEnabled(true);
|
||||
ignoreBtn.setEnabled(true);
|
||||
if (addWordProposal != null) {
|
||||
addWordBtn.setEnabled(true);
|
||||
}
|
||||
replaceAllBtn.setEnabled(true);
|
||||
ignoreAllBtn.setEnabled(true);
|
||||
checkWordBtn.setEnabled(true);
|
||||
}
|
||||
} else { // skip locked text ranges
|
||||
if (foundProperNoun) {
|
||||
scanForErrors();
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip "misspellings" that contain numbers. I use Matcher here because
|
||||
// for some reason, Eclipse's spell checker API's preference for this
|
||||
// does absolutely nothing.
|
||||
// TODO: Remove this code when Eclipse spell checking properly respects
|
||||
// PreferenceConstants.SPELLING_IGNORE_DIGITS
|
||||
Matcher containsDigits = DIGITS.matcher(badWord);
|
||||
if (containsDigits.find()) {
|
||||
scanForErrors();
|
||||
/*
|
||||
* We have an actual spelling error to present to the user, so now let's
|
||||
* update all the UI.
|
||||
*/
|
||||
misspelledLbl.setText(badWord);
|
||||
suggestionList.setItems(suggestions.toArray(new String[0]));
|
||||
if (suggestionList.getItemCount() > 0) {
|
||||
suggestionList.select(0);
|
||||
replaceWithTF.setText(suggestionList.getItem(0));
|
||||
}
|
||||
|
||||
styledText.showSelection();
|
||||
replaceBtn.setEnabled(true);
|
||||
ignoreBtn.setEnabled(true);
|
||||
if (addWordProposal != null) {
|
||||
addWordBtn.setEnabled(true);
|
||||
}
|
||||
replaceAllBtn.setEnabled(true);
|
||||
ignoreAllBtn.setEnabled(true);
|
||||
checkWordBtn.setEnabled(true);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -646,7 +585,20 @@ public class SpellCheckDlg extends Dialog implements ISpellingProblemCollector {
|
|||
IDocument dummyDoc = new Document();
|
||||
addWordProposal.apply(dummyDoc);
|
||||
try {
|
||||
userDLFile.save();
|
||||
/*
|
||||
* TODO how will this work in later iterations of the
|
||||
* Localization API? Right now the eclipse internal spell
|
||||
* checker engine controls reads/writes to our locally
|
||||
* cached version of the file. We call save here to send the
|
||||
* updated file up to the localization store.
|
||||
*
|
||||
* Probably need to consider sub-classing the eclipse spell
|
||||
* checker in a way that allows us to control writes to the
|
||||
* localization files to prevent potential collision issues
|
||||
* with multiple users trying to update the SITE-level
|
||||
* dictionary.
|
||||
*/
|
||||
siteDictionary.save();
|
||||
} catch (Exception e) {
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
"Error saving user dictionary", e);
|
||||
|
@ -926,44 +878,113 @@ public class SpellCheckDlg extends Dialog implements ISpellingProblemCollector {
|
|||
xstore.setValue(PreferenceConstants.SPELLING_IGNORE_MIXED, false);
|
||||
xstore.setValue(PreferenceConstants.SPELLING_IGNORE_UPPER, false);
|
||||
xstore.setValue(PreferenceConstants.SPELLING_IGNORE_SENTENCE, true);
|
||||
// In SpellCheckDlg.accept() above, we do the work of this preference,
|
||||
// since the spell checker will still return errors that contain digits.
|
||||
xstore.setValue(PreferenceConstants.SPELLING_IGNORE_DIGITS, true);
|
||||
xstore.setValue(PreferenceConstants.SPELLING_IGNORE_DIGITS, false);
|
||||
xstore.setValue(PreferenceConstants.SPELLING_IGNORE_NON_LETTERS, true);
|
||||
xstore.setValue(PreferenceConstants.SPELLING_IGNORE_SINGLE_LETTERS,
|
||||
true);
|
||||
|
||||
// Find/create the user dictionary
|
||||
// Since eclipse doesn't support more than a master and user dictionary,
|
||||
// we have a master user dictionary template which contains common words
|
||||
// not in our master dictionary.
|
||||
IPathManager pathManager = PathManagerFactory.getPathManager();
|
||||
LocalizationContext ctx = pathManager.getContext(
|
||||
LocalizationType.CAVE_STATIC, LocalizationLevel.USER);
|
||||
userDLFile = pathManager.getLocalizationFile(ctx, SPELLDICT);
|
||||
if (!userDLFile.exists()) {
|
||||
File userDFile = userDLFile.getFile();
|
||||
if (!userDFile.exists()) {
|
||||
try {
|
||||
userDFile.createNewFile();
|
||||
LocalizationFile defaultDLFile = pathManager
|
||||
.getLocalizationFile(pathManager.getContext(
|
||||
LocalizationType.CAVE_STATIC,
|
||||
LocalizationLevel.BASE), SPELLDICT);
|
||||
FileUtil.copyFile(defaultDLFile.getFile(), userDFile);
|
||||
userDLFile.save();
|
||||
} catch (IOException e) {
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
"Error creating user dictionary", e);
|
||||
} catch (LocalizationException e) {
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
"Error creating user dictionary", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
String pathSpec = userDLFile.getFile().getAbsolutePath();
|
||||
xstore.setValue(PreferenceConstants.SPELLING_USER_DICTIONARY, pathSpec);
|
||||
xstore.setValue(PreferenceConstants.SPELLING_USER_DICTIONARY,
|
||||
siteDictionary.getFile().getAbsolutePath());
|
||||
xstore.setValue(PreferenceConstants.SPELLING_USER_DICTIONARY_ENCODING,
|
||||
DICTIONARY_ENCODING);
|
||||
}
|
||||
|
||||
private LocalizationFile getAdditionalDictionary() {
|
||||
/*
|
||||
* Since eclipse doesn't support more than a master and user dictionary,
|
||||
* we have a master user dictionary template (which we install at SITE
|
||||
* level) which contains common words not in our master dictionary.
|
||||
*/
|
||||
IPathManager pathManager = PathManagerFactory.getPathManager();
|
||||
LocalizationContext siteCtx = pathManager.getContext(
|
||||
LocalizationType.CAVE_STATIC, LocalizationLevel.SITE);
|
||||
LocalizationFile siteDictionary = pathManager.getLocalizationFile(
|
||||
siteCtx, SPELLDICT);
|
||||
if (!siteDictionary.exists()) {
|
||||
LocalizationContext baseCtx = pathManager.getContext(
|
||||
LocalizationType.CAVE_STATIC, LocalizationLevel.BASE);
|
||||
LocalizationFile dictionaryTemplate = pathManager
|
||||
.getLocalizationFile(baseCtx, SPELLDICT);
|
||||
|
||||
try (SaveableOutputStream outStream = siteDictionary
|
||||
.openOutputStream();
|
||||
InputStream inStream = dictionaryTemplate.openInputStream()) {
|
||||
byte[] copyBuffer = new byte[4096];
|
||||
while (inStream.available() > 0) {
|
||||
int bytesRead = inStream.read(copyBuffer);
|
||||
outStream.write(copyBuffer, 0, bytesRead);
|
||||
}
|
||||
outStream.save();
|
||||
} catch (IOException | LocalizationException e) {
|
||||
statusHandler.error("Error creating site spelling dictionary.",
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
return siteDictionary;
|
||||
}
|
||||
|
||||
/**
|
||||
* The event handler for the check word button. It doubles as the problem
|
||||
* collector for its internal SpellCheckJob.
|
||||
*
|
||||
* @author wldougher
|
||||
*/
|
||||
class CheckWord extends SelectionAdapter implements
|
||||
ISpellingProblemCollector {
|
||||
|
||||
private SpellCheckJob wordCheckJob;
|
||||
|
||||
private SpellingProblem wordProblem;
|
||||
|
||||
/*
|
||||
* If there's a spelling problem with the replacement word, save the
|
||||
* fact that it was wrong and jump to the end.
|
||||
*
|
||||
* @see
|
||||
* org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#accept
|
||||
* (org.eclipse.ui.texteditor.spelling.SpellingProblem)
|
||||
*/
|
||||
@Override
|
||||
public void accept(SpellingProblem problem) {
|
||||
wordProblem = problem;
|
||||
endCollecting();
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* @seeorg.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#
|
||||
* beginCollecting()
|
||||
*/
|
||||
@Override
|
||||
public void beginCollecting() {
|
||||
wordProblem = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the user if the replacement word is spelled correctly or not.
|
||||
*
|
||||
* @seeorg.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#
|
||||
* endCollecting
|
||||
* ()
|
||||
*/
|
||||
@Override
|
||||
public void endCollecting() {
|
||||
if (wordProblem == null) {
|
||||
wordCheckLbl.setText("The word is correct");
|
||||
} else {
|
||||
wordCheckLbl.setText(wordProblem.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The action taken when the check word button is clicked.
|
||||
*/
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent evt) {
|
||||
wordCheckJob = new SpellCheckJob("wordCheck");
|
||||
wordCheckJob.setCollector(this);
|
||||
wordCheckJob.setText(replaceWithTF.getText());
|
||||
wordCheckJob.schedule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,7 +113,6 @@ import com.raytheon.uf.viz.spellchecker.dialogs.SpellCheckDlg;
|
|||
import com.raytheon.viz.core.mode.CAVEMode;
|
||||
import com.raytheon.viz.gfe.Activator;
|
||||
import com.raytheon.viz.gfe.GFEPreference;
|
||||
import com.raytheon.viz.gfe.constants.StatusConstants;
|
||||
import com.raytheon.viz.gfe.core.DataManager;
|
||||
import com.raytheon.viz.gfe.dialogs.formatterlauncher.ConfigData.ProductStateEnum;
|
||||
import com.raytheon.viz.gfe.product.ProductFileUtil;
|
||||
|
@ -849,9 +848,8 @@ public class ProductEditorComp extends Composite implements
|
|||
@Override
|
||||
public void widgetSelected(SelectionEvent event) {
|
||||
SpellCheckDlg spellCheckDlg = new SpellCheckDlg(parent
|
||||
.getShell(), ProductEditorComp.this.getTextEditorST(),
|
||||
StatusConstants.CATEGORY_GFE,
|
||||
StatusConstants.SUBCATEGORY_TEXTFORMATTER);
|
||||
.getShell(), getTextEditorST(), MixedCaseProductSupport
|
||||
.isMixedCase(getNNNid()));
|
||||
spellCheckDlg.open();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -150,7 +150,6 @@ import com.raytheon.uf.viz.core.auth.UserController;
|
|||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.uf.viz.core.notification.jobs.NotificationManagerJob;
|
||||
import com.raytheon.uf.viz.core.requests.ThriftClient;
|
||||
import com.raytheon.uf.viz.core.status.StatusConstants;
|
||||
import com.raytheon.uf.viz.spellchecker.dialogs.SpellCheckDlg;
|
||||
import com.raytheon.uf.viz.ui.menus.DiscoverMenuContributions;
|
||||
import com.raytheon.viz.core.mode.CAVEMode;
|
||||
|
@ -350,6 +349,7 @@ import com.raytheon.viz.ui.dialogs.SWTMessageBox;
|
|||
* 15Jun2015 4441 randerso Unconditionally convert text to upper case for QC
|
||||
* 8Jul2015 DR 15044 dhuffman Implemented tabbing and tabs to spaces.
|
||||
* Aug 31, 2015 4749 njensen Changed setCloseCallback to addCloseCallback
|
||||
* Sep 02, 2015 4781 dgilling Used different constructor for SpellCheckDlg.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -3993,8 +3993,9 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
|
|||
int numberOfSpaces = (textEditor.getTabs() - caretOffsetOnLine
|
||||
% textEditor.getTabs());
|
||||
String spaces = "";
|
||||
for (int x = 0; x < numberOfSpaces; x++)
|
||||
for (int x = 0; x < numberOfSpaces; x++) {
|
||||
spaces += ' ';
|
||||
}
|
||||
textEditor.insert(spaces);
|
||||
textEditor.setCaretOffset(textEditor.getCaretOffset()
|
||||
+ numberOfSpaces);
|
||||
|
@ -6591,9 +6592,9 @@ public class TextEditorDialog extends CaveSWTDialog implements VerifyListener,
|
|||
* Displays the spell checker dialog to initiate spell checking.
|
||||
*/
|
||||
private void checkSpelling() {
|
||||
StdTextProduct product = getStdTextProduct();
|
||||
SpellCheckDlg spellCheckDlg = new SpellCheckDlg(shell, textEditor,
|
||||
StatusConstants.CATEGORY_WORKSTATION,
|
||||
StatusConstants.SUBCATEGORY_CONNECTIVITY);
|
||||
MixedCaseProductSupport.isMixedCase(product.getNnnid()));
|
||||
spellCheckDlg.open();
|
||||
}
|
||||
|
||||
|
|
158
deltaScripts/16.2.1/DR4781/migrateUserSpellingDictionaries.py
Executable file
158
deltaScripts/16.2.1/DR4781/migrateUserSpellingDictionaries.py
Executable file
|
@ -0,0 +1,158 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import errno
|
||||
import glob
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
|
||||
BASH_COMMAND = ['bash', '-c']
|
||||
SOURCE_COMMAND_FORMAT = 'source {} && env'
|
||||
SETUP_ENV_FILE = '/awips2/edex/bin/setup.env'
|
||||
USER_DICT_GLOB_PATTERN = '/awips2/edex/data/utility/cave_static/user/*/spelldict'
|
||||
CAVE_STATIC_SITE_LEVEL_PATH = '/awips2/edex/data/utility/cave_static/site/'
|
||||
COMMON_STATIC_SITE_LEVEL_PATH = '/awips2/edex/data/utility/common_static/site/'
|
||||
EDEX_STATIC_SITE_LEVEL_PATH = '/awips2/edex/data/utility/edex_static/site/'
|
||||
SVC_BU_PROPS_PATH = 'config/gfe/svcbu.properties'
|
||||
USER_ROLES_PATH = 'roles/userRoles.xml'
|
||||
NEW_DICT_PATH = 'spellchecker/spelldict.txt'
|
||||
NEW_ROLE_ID = 'com.raytheon.localization.site/cave_static/spellchecker'
|
||||
|
||||
|
||||
logging.basicConfig(format="%(asctime)s %(levelname)s: %(message)s",
|
||||
datefmt="%H:%M:%S",
|
||||
level=logging.DEBUG)
|
||||
log = logging.getLogger('migrateUserSpellingDictionaries')
|
||||
|
||||
|
||||
def createDir(dir):
|
||||
try:
|
||||
os.makedirs(os.path.dirname(dir))
|
||||
except OSError as e:
|
||||
if e.errno != errno.EEXIST:
|
||||
raise
|
||||
|
||||
def sourceEnvFileGetVariable(envFile, variable):
|
||||
cmdArray = list(BASH_COMMAND)
|
||||
cmdArray.append(SOURCE_COMMAND_FORMAT.format(envFile))
|
||||
output = subprocess.check_output(cmdArray)
|
||||
for line in output.splitlines():
|
||||
if variable in line:
|
||||
tokens = line.split('=')
|
||||
return tokens[1].strip()
|
||||
return ''
|
||||
|
||||
def getSiteID():
|
||||
try:
|
||||
return sourceEnvFileGetVariable(SETUP_ENV_FILE, "AW_SITE_IDENTIFIER")
|
||||
except subprocess.CalledProcessError as e:
|
||||
log.exception("Could not process [%s].", os.path.basename(SETUP_ENV_FILE))
|
||||
return ''
|
||||
|
||||
def getPrimarySites(awSiteID):
|
||||
svcBuPropsFile = os.path.join(EDEX_STATIC_SITE_LEVEL_PATH, awSiteID, SVC_BU_PROPS_PATH)
|
||||
if os.path.isfile(svcBuPropsFile):
|
||||
siteList = sourceEnvFileGetVariable(svcBuPropsFile, "PRIMARY_SITES")
|
||||
if siteList:
|
||||
return [site.strip() for site in siteList.split(',')]
|
||||
return []
|
||||
|
||||
def main():
|
||||
log.info("Running delta script for DR 4781: migrating USER spelling dictionaries to SITE.")
|
||||
|
||||
userDicts = glob.glob(USER_DICT_GLOB_PATTERN)
|
||||
combinedDict = set()
|
||||
for userDict in userDicts:
|
||||
log.info("Migrating USER-level spelling dictionary [%s].", userDict)
|
||||
try:
|
||||
with open(userDict, 'r') as f:
|
||||
spelling_entries = f.readlines()
|
||||
combinedDict = combinedDict.union(spelling_entries)
|
||||
except IOError:
|
||||
log.warning("Skipping USER-level spelling dictionary [%s].", userDict, exc_info=1)
|
||||
|
||||
siteID = getSiteID()
|
||||
if not siteID:
|
||||
log.error("Could not determine this server's site ID.")
|
||||
log.error("Delta script failed.")
|
||||
return -1
|
||||
|
||||
siteDictFile = os.path.join(CAVE_STATIC_SITE_LEVEL_PATH, siteID, NEW_DICT_PATH)
|
||||
log.info("Writing SITE-level spelling dictionary [%s].", siteDictFile)
|
||||
try:
|
||||
createDir(os.path.dirname(siteDictFile))
|
||||
with open(siteDictFile, 'w') as f:
|
||||
f.writelines(sorted(combinedDict))
|
||||
except OSError:
|
||||
log.exception("Could not create SITE directory for spelling dictionary.")
|
||||
log.error("Delta script failed.")
|
||||
return -1
|
||||
except IOError:
|
||||
log.exception("Could not write SITE spelling dictionary.")
|
||||
log.error("Delta script failed.")
|
||||
return -1
|
||||
except Exception:
|
||||
log.exception("Unknown error trying to create SITE spelling dictionary.")
|
||||
log.error("Delta script failed.")
|
||||
return -1
|
||||
|
||||
log.info("Updating userRoles.xml.")
|
||||
siteUserRoles = os.path.join(COMMON_STATIC_SITE_LEVEL_PATH, siteID, USER_ROLES_PATH)
|
||||
if os.path.isfile(siteUserRoles):
|
||||
tree = ET.parse(siteUserRoles)
|
||||
root = tree.getroot()
|
||||
root.set('xmlns:ns2', 'group')
|
||||
newPermission = ET.SubElement(root, "permission", {'id':NEW_ROLE_ID})
|
||||
users = root.findall("user")
|
||||
for user in users:
|
||||
if user.get("userId") == "ALL":
|
||||
newUserPermission = ET.SubElement(user, "userPermission")
|
||||
newUserPermission.text = NEW_ROLE_ID
|
||||
roughString = ET.tostring(root, 'utf-8')
|
||||
finalString = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' + '\n' + roughString
|
||||
try:
|
||||
with open(siteUserRoles, 'w') as f:
|
||||
f.write(finalString)
|
||||
except IOError:
|
||||
log.exception("Could not update SITE-level userRoles.xml.")
|
||||
log.error("Delta script failed.")
|
||||
return -1
|
||||
except Exception:
|
||||
log.exception("Unknown error trying to update SITE-level userRoles.xml.")
|
||||
log.error("Delta script failed.")
|
||||
return -1
|
||||
|
||||
gfeSites = []
|
||||
try:
|
||||
gfeSites = getPrimarySites(siteID)
|
||||
except Exception as e:
|
||||
log.exception("Could not retrieve PRIMARY_SITES setting.")
|
||||
log.error("Delta script failed.")
|
||||
return -1
|
||||
|
||||
for site in gfeSites:
|
||||
gfeSiteFile = os.path.join(CAVE_STATIC_SITE_LEVEL_PATH, site, NEW_DICT_PATH)
|
||||
log.info("Writing SITE-level spelling dictionary [%s].", gfeSiteFile)
|
||||
try:
|
||||
createDir(os.path.dirname(gfeSiteFile))
|
||||
shutil.copy(siteDictFile, gfeSiteFile)
|
||||
except OSError:
|
||||
log.exception("Could not create SITE directory for spelling dictionary.")
|
||||
log.error("Delta script failed.")
|
||||
return -1
|
||||
except IOError:
|
||||
log.exception("Could not write SITE spelling dictionary.")
|
||||
log.error("Delta script failed.")
|
||||
return -1
|
||||
except Exception:
|
||||
log.exception("Unknown error trying to create SITE spelling dictionary.")
|
||||
log.error("Delta script failed.")
|
||||
return -1
|
||||
|
||||
log.info("Delta script complete.")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -83,6 +83,9 @@
|
|||
<permission id="com.raytheon.localization.site/cave_static/aviation/avnwatch">
|
||||
</permission>
|
||||
|
||||
<permission id="com.raytheon.localization.site/cave_static/spellchecker">
|
||||
</permission>
|
||||
|
||||
<permission id="com.raytheon.localization.site/common_static/radar/rmr/rmrAvailableRequests.xml">
|
||||
</permission>
|
||||
|
||||
|
@ -157,6 +160,7 @@
|
|||
<userPermission>com.raytheon.localization.site/common_static/python/events/productgen/formats</userPermission>
|
||||
<userPermission>com.raytheon.localization.site/common_static/python/events/recommenders</userPermission>
|
||||
<userPermission>com.raytheon.localization.site/common_static/python/textUtilities</userPermission>
|
||||
<userPermission>com.raytheon.localization.site/cave_static/spellchecker</userPermission>
|
||||
</user>
|
||||
</nwsRoleData>
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue