import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.text.*; /** The swing version of the reverse applet/application.
Text typed into either of the 2 text areas will appear reversed in the other one.
May be run either as applet or application */ public class Reverse extends JApplet { JTextArea original, reversed; Document originalDocument, reversedDocument; public static void pl(Object o) { System.out.println(o.toString()); } int ignoreCount = 0; /* So far as I can tell, there is no straightforward way to to tell if a documentEvent was triggered by the user (e.g. keystrokes) or by the computer (i.e. setText()) So, we have to second-guess what swing is doing, which is different from what awt does. In the awt, setText() generates a single atomic text-change event. Very simple -- a boolean 'ignore' toggle is sufficient. In swing, setText() has a special case for empty text. If we are removing all, or the document was empty to begin with, then only one event (remove, insert, respectively) gets generated. However, if the text was not empty or will not be empty after the alteration, TWO Events get generated: one to remove all, the next to insert the text. With any luck, this behavior will remain consistent. */ class reverseTextListener implements DocumentListener { void updateViews(DocumentEvent e) { //Thread.dumpStack(); Document doc=e.getDocument(); // at this point, the text change has not happened yet. if (ignoreCount > 0) { --ignoreCount; return; } ignoreCount = 2; if (reversed.getText().length() == 0 || original.getText().length() == 0) ignoreCount--; if (doc == originalDocument) { String rev = new StringBuffer(original.getText()).reverse().toString(); if (!reversed.getText().equals(rev)) { reversed.setText(rev); } } else if (doc == reversedDocument) { String rev = new StringBuffer(reversed.getText()).reverse().toString(); if (!original.getText().equals(rev)) { original.setText(rev); } } //System.out.println("document changed."); } public String whichDocument(Document doc) { if (doc == originalDocument) return "original"; if (doc == reversedDocument) return "reversed"; return "unknown"; } public void insertUpdate(DocumentEvent e) { //pl("insertUpdate("+whichDocument(e.getDocument())+")" + e); updateViews(e); } public void removeUpdate(DocumentEvent e) { //pl("removeUpdate("+whichDocument(e.getDocument())+")" + e); updateViews(e); } public void changedUpdate(DocumentEvent e) { //pl("changedUpdate("+whichDocument(e.getDocument())+")" + e); updateViews(e); } } public static void centerWindow(Window w) { if (w == null) return; try { Dimension d=w.getSize(); Dimension maxD=w.getToolkit().getScreenSize(); w.setLocation((maxD.width - d.width) / 2, (maxD.height - d.height) / 2); } catch (NullPointerException e) { // the window probably got disappeared } } public Reverse() { Container contents = getContentPane(); original = new JTextArea(8,60); original.setBackground(Color.white); (originalDocument = original.getDocument()) .addDocumentListener(new reverseTextListener()); reversed = new JTextArea(8,60); reversed.setBackground(new Color(0,30,60)); reversed.setForeground(Color.white); (reversedDocument = reversed.getDocument()) .addDocumentListener(new reverseTextListener()); contents.setLayout(new BoxLayout(contents, BoxLayout.Y_AXIS)); contents.add(new JScrollPane(original)); contents.add(new JLabel("type into either text area.")); contents.add(new JScrollPane(reversed)); } public static void main(String args[]) { JFrame frame = new JFrame("reverse"); frame.getContentPane().add(new Reverse()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); centerWindow(frame); frame.show(); } }