# 4
Thanks for the info, it sounds like this will work but I am not completely sure that I understand where to place this event code. I can move the Spell Check Listener to be interfaced in another class if need be. I am attaching the complete code that I have currently. If you could please give me a little more insight into where I should place these threads, listeners, and event queues I would greatly appreciate it.
This spell checker is based on Jazzy Spell Checker.
This class is just a gui form thrown together for testing, this will be replaced by a Oracle Form.
package spellchecker;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import oracle.forms.ui.VTextArea;
public class SpellBox extends JFrame {
private BorderLayout borderLayout1 = new BorderLayout();
private JButton btnSpellCheck = new JButton();
private VTextArea txtSpellCheck = new VTextArea();
private SpellCheckThis checkit = new SpellCheckThis();
public SpellBox() {
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
try {
jbInit();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SpellBox app = new SpellBox();
System.out.println("Showing form");
app.setVisible(true);
}
private void jbInit() throws Exception {
this.setSize(new Dimension(642, 334));
this.setLayout(borderLayout1);
this.setResizable(false);
this.setLocation(350, 350);
btnSpellCheck.setText("Spell Check That Thang!");
this.add(btnSpellCheck, BorderLayout.NORTH);
this.getContentPane().add(txtSpellCheck, BorderLayout.CENTER);
btnSpellCheck.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
checkit.spellCheck(txtSpellCheck);
}
});
}
}
This class will become an implimentation class for an Oracle Form
package spellchecker;
import com.swabunga.spell.engine.SpellDictionary;
import com.swabunga.spell.engine.SpellDictionaryHashMap;
import com.swabunga.spell.event.SpellCheckEvent;
import com.swabunga.spell.event.SpellCheckListener;
import com.swabunga.spell.event.SpellChecker;
import com.swabunga.spell.event.StringWordTokenizer;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.TextEvent;
import java.awt.event.TextListener;
import java.io.File;
import java.util.StringTokenizer;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.text.Highlighter;
import jregex.MatchIterator;
import jregex.MatchResult;
import jregex.Matcher;
import jregex.Pattern;
import oracle.ewt.ColorScheme;
import oracle.ewt.lwAWT.LWComponent;
import oracle.ewt.lwAWT.lwText.LWTextArea;
import oracle.ewt.lwAWT.lwText.LWTextComponent;
import oracle.ewt.lwAWT.lwText.SelectionEvent;
import oracle.ewt.lwAWT.lwText.SelectionListener;
import oracle.ewt.painter.PaintContext;
import oracle.ewt.painter.Painter;
import oracle.ewt.painter.TextPainter;
import oracle.forms.handler.TextAreaItem;
import oracle.forms.properties.FormAction;
import oracle.forms.ui.VTextArea;
import oracle.graphics.vgs.ui.Text;
public class SpellCheckThis {
public LWTextArea lwtext = null;
public SpellCheckFrame spellPane = null;
public SpellCheckThis call = this;
public SpellCheckThis() {
}
public void spellCheck(VTextArea txtSpellCheck) {
lwtext = (LWTextArea)txtSpellCheck.getComponent(0);
Thread t = new Thread() {
public void run() {
try {
spellPane = new SpellCheckFrame(lwtext.getText(), call);
if (!spellPane.getErrors())
JOptionPane.showMessageDialog(null, "No Errors Found", "Velocity Spell Check",
JOptionPane.INFORMATION_MESSAGE);
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
t.start();
}
public void setLwtext(String text) {
this.lwtext.setText(text);
}
}
And finally, this is currently the class that does all the displaying and spell checking.
package spellchecker;
import com.swabunga.spell.engine.Configuration;
import com.swabunga.spell.engine.SpellDictionary;
import com.swabunga.spell.engine.SpellDictionaryHashMap;
import com.swabunga.spell.engine.Word;
import com.swabunga.spell.event.SpellCheckEvent;
import com.swabunga.spell.event.SpellCheckListener;
import com.swabunga.spell.event.SpellChecker;
import com.swabunga.spell.event.StringWordTokenizer;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.StringTokenizer;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.border.BevelBorder;
import javax.swing.event.EventListenerList;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import jregex.MatchIterator;
import jregex.MatchResult;
import jregex.Matcher;
import jregex.Pattern;
import nl.jj.swingx.gui.modal.InputBlocker;
public class SpellCheckFrame extends JDialog implements ActionListener, ListSelectionListener, SpellCheckListener {
private static final String dictFile = "english.0";
// private static final File dictFile = new File(VRCFile._LibDir(), "english.0");
public static final String IGNORE_CMD = "IGNORE";
public static final String IGNOREALL_CMD = "IGNOREALL";
public static final String ADD_CMD = "ADD";
public static final String REPLACE_CMD = "REPLACE";
public static final String REPLACEALL_CMD = "REPLACEALL";
public static final String CANCEL_CMD = "CANCEL";
public static final String DONE_CMD = "DONE";
public static final String ADDWORD_1 = "ADDWORD_1";
public static final String ADDWORD_2 = "ADDWORD_2";
public static final String ADDWORD_3 = "ADDWORD_3";
private boolean errors = false;
private boolean top = true;
private int spellErrors = 0;
private BorderLayout borderLayout1 = new BorderLayout();
private JPanel pnlWord = new JPanel();
private JPanel pnlOptions = new JPanel();
private JPanel pnlSuggestions = new JPanel();
private JLabel lblBadWord = new JLabel();
private JButton btnChange = new JButton();
private JButton btnChangeAll = new JButton();
private JButton btnIgnore = new JButton();
private JButton btnIgnoreAll = new JButton();
private JButton btnAdd = new JButton();
private JButton btnCancel = new JButton();
private JLabel lblSuggestions = new JLabel();
private JList lstSuggestions = new JList();
private SpellCheckEvent spellEvent = null;
private SpellCheckThis callback;
// private VSpellChecker callback;
private JTextArea txtSpellCheck = new JTextArea();
private JTextField txtWord = new JTextField();
private FlowLayout flowLayout1 = new FlowLayout();
private FlowLayout flowLayout2 = new FlowLayout();
private FlowLayout flowLayout3 = new FlowLayout();
private JButton btnDone = new JButton();
private JScrollPane scrollList = null;
private JScrollPane scrollPanel = null;
protected ResourceBundle messages;
protected EventListenerList listenerList = new EventListenerList();
public SpellChecker spellCheck = null;
/**
* Opens the Velocity Spell Check Interface and checks the spelling of the text passed to it
* @param text
* @param callback
*/
public SpellCheckFrame(String text, SpellCheckThis callback) {
txtSpellCheck.setText(text);
this.setModal(true);
//Set the Rows for the JTextArea for Scrolling
StringTokenizer tok = new StringTokenizer(text, "\n");
txtSpellCheck.setRows(tok.countTokens());
//Create backward connection to calling class
this.callback = callback;
try {
jbInit();
} catch (Exception e) {
}
//Set up the Dictionaries and start the Spell Check
messages = ResourceBundle.getBundle("com.swabunga.spell.swing.messages", Locale.getDefault());
try {
SpellDictionary dictionary =
new SpellDictionaryHashMap(new File("C:/java/Jazzy/english.0/" + dictFile));
//SpellDictionary dictionary =
//new SpellDictionaryHashMap(dictFile);
spellCheck = new SpellChecker(dictionary);
spellCheck.setCache();
spellCheck.setUserDictionary(dictionary);
spellCheck.addSpellCheckListener(this);
spellCheck.getConfiguration().setBoolean(Configuration.SPELL_IGNOREUPPERCASE, false);
spellCheck.checkSpelling(new StringWordTokenizer(txtSpellCheck.getText()));
} catch (Exception e) {
e.printStackTrace();
}
}
private void jbInit() throws Exception {
//Set Up JDialog
this.getContentPane().setLayout(borderLayout1);
this.setBackground(new Color(198, 198, 198));
this.setSize(new Dimension(550, 460));
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.setTitle("Velocity Spell Check");
this.setResizable(false);
//this.addWindowListener(new WindowAdapter() {
// public void windowDeactivated(WindowEvent e) {
//this_windowDeactivated(e);
// }
//});
//Create North Panel
pnlWord.setBackground(new Color(231, 231, 231));
pnlWord.setBounds(new Rectangle(0, 0, 395, 100));
pnlWord.setSize(new Dimension(400, 57));
pnlWord.setLayout(flowLayout1);
pnlWord.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
pnlWord.setMinimumSize(new Dimension(395, 57));
pnlWord.setMaximumSize(new Dimension(400, 57));
pnlWord.setPreferredSize(new Dimension(395, 220));
txtSpellCheck.setLineWrap(true);
txtSpellCheck.setCaret(new SelectionCaret());
txtSpellCheck.setPreferredSize(new Dimension(525, 180));
txtSpellCheck.setSize(new Dimension(525, 180));
txtSpellCheck.setMinimumSize(new Dimension(525, 180));
txtSpellCheck.setMaximumSize(new Dimension(525, 180));
scrollPanel = new JScrollPane(txtSpellCheck);
scrollPanel.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPanel.setAutoscrolls(true);
scrollPanel.setPreferredSize(new Dimension(534, 180));
scrollPanel.setSize(new Dimension(534, 180));
scrollPanel.setMaximumSize(new Dimension(534, 180));
scrollPanel.setMinimumSize(new Dimension(534, 180));
lblBadWord.setText("Mispelled Word: ");
lblBadWord.setFont(new Font("Tahoma", 1, 13));
lblBadWord.setPreferredSize(new Dimension(210, 18));
lblBadWord.setSize(new Dimension(210, 18));
lblBadWord.setMinimumSize(new Dimension(210, 18));
lblBadWord.setMaximumSize(new Dimension(210, 18));
txtWord.setPreferredSize(new Dimension(319, 22));
txtWord.setSize(new Dimension(319, 22));
txtWord.setMinimumSize(new Dimension(319, 22));
txtWord.setMaximumSize(new Dimension(319, 22));
txtWord.setBorder(BorderFactory.createLineBorder(Color.black, 1));
pnlWord.add(scrollPanel, null);
pnlWord.add(lblBadWord, null);
pnlWord.add(txtWord, null);
//Create Center Panel
pnlSuggestions.setBackground(new Color(231, 231, 231));
pnlSuggestions.setLayout(flowLayout2);
pnlSuggestions.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
pnlSuggestions.setPreferredSize(new Dimension(254, 199));
pnlSuggestions.setSize(new Dimension(254, 199));
pnlSuggestions.setMinimumSize(new Dimension(254, 199));
pnlSuggestions.setMaximumSize(new Dimension(254, 199));
lblSuggestions.setText("Suggestions:");
lblSuggestions.setFont(new Font("Tahoma", 1, 13));
lblSuggestions.setPreferredSize(new Dimension(391, 18));
lblSuggestions.setSize(new Dimension(391, 18));
lblSuggestions.setMinimumSize(new Dimension(391, 18));
lblSuggestions.setMaximumSize(new Dimension(391, 18));
lstSuggestions.setValueIsAdjusting(true);
lstSuggestions.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
lstSuggestions.setBorder(BorderFactory.createLineBorder(Color.black, 1));
lstSuggestions.setVisibleRowCount(100);
lstSuggestions.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
lstSuggestions_valueChanged(e);
}
});
scrollList = new JScrollPane(lstSuggestions);
scrollList.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollList.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollList.setPreferredSize(new Dimension(391, 174));
scrollList.setSize(new Dimension(391, 174));
scrollList.setMinimumSize(new Dimension(391, 174));
scrollList.setMaximumSize(new Dimension(391, 174));
pnlSuggestions.add(lblSuggestions);
pnlSuggestions.add(scrollList);
//Create East Panel
pnlOptions.setBackground(new Color(198, 198, 198));
pnlOptions.setLayout(flowLayout3);
pnlOptions.setPreferredSize(new Dimension(143, 199));
pnlOptions.setMinimumSize(new Dimension(143, 199));
pnlOptions.setMaximumSize(new Dimension(143, 199));
btnChange.setText("Change");
btnChange.setActionCommand("REPLACE");
btnChange.setPreferredSize(new Dimension(133, 24));
btnChange.setMinimumSize(new Dimension(133, 24));
btnChange.setMaximumSize(new Dimension(133, 24));
btnChange.addActionListener(this);
btnChangeAll.setText("Change All");
btnChangeAll.setActionCommand("REPLACEALL");
btnChangeAll.setPreferredSize(new Dimension(133, 24));
btnChangeAll.setMaximumSize(new Dimension(133, 24));
btnChangeAll.setMinimumSize(new Dimension(133, 24));
btnChangeAll.addActionListener(this);
btnIgnore.setText("Ignore");
btnIgnore.setActionCommand("IGNORE");
btnIgnore.setPreferredSize(new Dimension(133, 24));
btnIgnore.setMaximumSize(new Dimension(133, 24));
btnIgnore.setMinimumSize(new Dimension(133, 24));
btnIgnore.addActionListener(this);
btnIgnoreAll.setText("Ignore All");
btnIgnoreAll.setActionCommand("IGNOREALL");
btnIgnoreAll.setPreferredSize(new Dimension(133, 24));
btnIgnoreAll.setMaximumSize(new Dimension(133, 24));
btnIgnoreAll.setMinimumSize(new Dimension(133, 24));
btnIgnoreAll.addActionListener(this);
btnAdd.setText("Add To Dictionary");
btnAdd.setActionCommand("ADD");
btnAdd.setPreferredSize(new Dimension(133, 24));
btnAdd.setMaximumSize(new Dimension(133, 24));
btnAdd.setMinimumSize(new Dimension(133, 24));
btnAdd.addActionListener(this);
btnCancel.setText("Cancel");
btnCancel.setActionCommand("CANCEL");
btnCancel.setPreferredSize(new Dimension(133, 24));
btnCancel.setMaximumSize(new Dimension(133, 24));
btnCancel.setMinimumSize(new Dimension(133, 24));
btnCancel.addActionListener(this);
btnDone.setText("Done");
btnDone.setActionCommand("DONE");
btnDone.setSize(new Dimension(133, 24));
btnDone.setPreferredSize(new Dimension(133, 24));
btnDone.setMaximumSize(new Dimension(133, 24));
btnDone.setMinimumSize(new Dimension(133, 24));
btnDone.addActionListener(this);
pnlOptions.add(btnChange, null);
pnlOptions.add(btnChangeAll, null);
pnlOptions.add(btnIgnore, null);
pnlOptions.add(btnIgnoreAll, null);
pnlOptions.add(btnAdd, null);
pnlOptions.add(btnCancel, null);
pnlOptions.add(btnDone, null);
//Add Panels to JDialog
this.getContentPane().add(pnlWord, BorderLayout.NORTH);
this.getContentPane().add(pnlSuggestions, BorderLayout.CENTER);
this.getContentPane().add(pnlOptions, BorderLayout.EAST);
}
public void valueChanged(ListSelectionEvent e) {
lstSuggestions_valueChanged(e);
}
private void lstSuggestions_valueChanged(ListSelectionEvent e) {
//Refresh value of the replacing word when selection changes
if ((!e.getValueIsAdjusting()) && (lstSuggestions.getSelectedValue() != null)) {
this.txtWord.setText(lstSuggestions.getSelectedValue().toString());
}
}
public void addActionListener(ActionListener l) {
//Register an action listener
listenerList.add(ActionListener.class, l);
}
public void removeActionListener(ActionListener l) {
//Deregister an action listener
listenerList.remove(ActionListener.class, l);
}
/**
* Called when the Spell Event encounters a mispelled word
* Sets the Mispelled Word and Suggestion List
* @param event
*/
public void spellingError(SpellCheckEvent event) {
spellErrors++;
spellEvent = event;
errors = true;
String badword = spellEvent.getInvalidWord();
//Highlight the mispelled word
txtSpellCheck.requestFocus();
txtSpellCheck.setCaretPosition(0);
txtSpellCheck.setCaretPosition(spellEvent.getWordContextPosition());
txtSpellCheck.moveCaretPosition(spellEvent.getWordContextPosition() + badword.length());
DefaultListModel m = new DefaultListModel();
//Get the Suggestions
List suggestions = event.getSuggestions();
//Test word for all Caps
char[] testWord = badword.toCharArray();
boolean capWord = true;
for (int i = 0; i < testWord.length && capWord; i++)
capWord = capWord && Character.isUpperCase(badword.charAt(i));
boolean cap =
(!spellCheck.getConfiguration().getBoolean(Configuration.SPELL_IGNOREUPPERCASE) && capWord);
//If mispelled word is all Caps, Capitalize the Suggestions
if (cap) {
Iterator iterator = suggestions.iterator();
while (iterator.hasNext()) {
Word word = (Word)iterator.next();
String suggestion = word.getWord();
word.setWord(suggestion.toUpperCase());
}
}
//Add Suggestions to the List
for (int i = 0; i < suggestions.size(); i++) {
m.addElement(suggestions.get(i));
}
lstSuggestions.setModel(m);
lblBadWord.setText("Mispelled Word: " + event.getInvalidWord());
if (m.size() > 0) {
lstSuggestions.setSelectedIndex(0);
txtWord.setText(((Word)m.get(0)).getWord());
} else {
txtWord.setText(event.getInvalidWord());
}
if (spellErrors == 1)this.setVisible(true);
//Stops application between Spelling Errors
synchronized (this) {
try {
this.wait();
} catch (InterruptedException e) {
}
}
}
/**
* Handles all button actions
* Parses by Action Command to execute corresponding Action
* @param e
*/
public void actionPerformed(ActionEvent e) {
try {
if (IGNORE_CMD.equals(e.getActionCommand())) {
spellEvent.ignoreWord(false);
} else if (IGNOREALL_CMD.equals(e.getActionCommand())) {
spellEvent.ignoreWord(true);
} else if (REPLACE_CMD.equals(e.getActionCommand())) {
spellEvent.replaceWord(txtWord.getText(), false);
this.spellCorrection(spellEvent);
} else if (REPLACEALL_CMD.equals(e.getActionCommand())) {
spellEvent.replaceWord(txtWord.getText(), true);
this.spellCorrection(spellEvent);
} else if (ADD_CMD.equals(e.getActionCommand())) {
String inField = txtWord.getText();
Object selObj = lstSuggestions.getSelectedValue();
String selected = (selObj == null ? "" : selObj.toString());
String addString = (inField.equals(selected) ? spellEvent.getInvalidWord() : inField);
top = false;
int n = JOptionPane.showConfirmDialog(this, messages.getString(ADDWORD_1) + " '" + addString +
"' " + messages.getString(ADDWORD_2),
messages.getString(ADDWORD_3), JOptionPane.YES_NO_OPTION);
top = true;
this.requestFocus();
if (n == JOptionPane.YES_OPTION) {
spellEvent.addToDictionary(addString);
} else {
return;
}
this.requestFocus();
} else if (CANCEL_CMD.equals(e.getActionCommand())) {
spellEvent.cancel();
this.dispose();
} else if (DONE_CMD.equals(e.getActionCommand())) {
callback.setLwtext(txtSpellCheck.getText());
spellEvent.cancel();
this.dispose();
}
//Resumes application
synchronized (this) {
this.notify();
}
fireActionEvent(e);
} catch (IllegalStateException state) {
//Closes Application, writes changes if the DONE button was pressed
btnChange.setEnabled(false);
btnChangeAll.setEnabled(false);
btnIgnore.setEnabled(false);
btnIgnoreAll.setEnabled(false);
btnAdd.setEnabled(false);
lstSuggestions.setEnabled(false);
txtWord.setEnabled(false);
if (DONE_CMD.equals(e.getActionCommand())) {
callback.setLwtext(txtSpellCheck.getText());
this.dispose();
} else if (CANCEL_CMD.equals(e.getActionCommand())) {
this.dispose();
}
}
}
protected void fireActionEvent(ActionEvent e) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length - 2; i >= 0; i -= 2) {
System.out.println(listeners[i].toString());
if (listeners[i] == ActionListener.class) {
((ActionListener)listeners[i + 1]).actionPerformed(e);
}
}
}
/**
* Replaces mispelled word with correct word
* Replaces one word or all words depending on button pressed
* @param event
*/
public void spellCorrection(SpellCheckEvent event) {
String word = event.getInvalidWord();
String correctWord = event.getReplaceWord();
if (event.getAction() == event.REPLACE) {
Pattern p = new Pattern("\\b" + word + "\\b");
Matcher m = p.matcher(txtSpellCheck.getText());
MatchIterator mi = m.findAll();
MatchResult mr = mi.nextMatch();
txtSpellCheck.replaceRange(correctWord, mr.start(), mr.end());
} else if (event.getAction() == event.REPLACEALL) {
txtSpellCheck.setText(new Pattern("\\b" + word + "\\b").replacer(correctWord)
.replace(txtSpellCheck.getText()));
}
// In java 1.4 we could have done this:
//if (event.getAction() == event.REPLACE){
//lwtext.setText(lwtext.getText().replaceFirst("\\b" + word + "\\b", correctWord));
//}else if (event.getAction() == event.REPLACEALL){
//lwtext.setText(lwtext.getText().replaceAll("\\b" + word + "\\b", correctWord));
//}
}
private void this_windowDeactivated(WindowEvent e) {
//Keeps Spell Check Window on top until closed
if (top)
SpellCheckFrame.this.requestFocus();
}
public boolean getErrors() {
return errors;
}
}