001: package abbot.editor.widgets;
002:
003: import java.awt.*;
004: import java.awt.event.*;
005: import javax.swing.*;
006: import javax.swing.event.*;
007: import java.util.*;
008:
009: import abbot.Log;
010:
011: /** A better text area that fires when focus leaves the component, and
012: also selects all the contents when the action is fired to indicate the
013: contents were accepted. */
014: // FIXME extend to have a "commit" on enter or focus change, where ESC will
015: // revert
016: public class TextArea extends JTextArea {
017:
018: public static final String ACTION_FOCUS_LOST = "focus-lost";
019: public static final String ACTION_TEXT_CHANGED = "text-changed";
020: public static final String ACTION_TEXT_INSERTED = "text-changed";
021: public static final String ACTION_TEXT_REMOVED = "text-changed";
022:
023: private boolean continuousFire = true;
024: private boolean fieldChanging = false;
025: private ArrayList listeners = new ArrayList();
026:
027: public TextArea(String value) {
028: super (value);
029: addFocusListener(new java.awt.event.FocusAdapter() {
030: public void focusLost(java.awt.event.FocusEvent ev) {
031: if (!ev.isTemporary() && !isLocalMenuActive()) {
032: Log.debug("Firing on focus loss");
033: fireActionPerformed(ACTION_FOCUS_LOST);
034: }
035: }
036: });
037: getDocument().addDocumentListener(new DocumentListener() {
038: public void changedUpdate(DocumentEvent ev) {
039: if (!fieldChanging && continuousFire)
040: fireActionPerformed(ACTION_TEXT_CHANGED);
041: }
042:
043: public void insertUpdate(DocumentEvent ev) {
044: if (!fieldChanging && continuousFire)
045: fireActionPerformed(ACTION_TEXT_INSERTED);
046: }
047:
048: public void removeUpdate(DocumentEvent ev) {
049: if (!fieldChanging && continuousFire)
050: fireActionPerformed(ACTION_TEXT_REMOVED);
051: }
052: });
053: }
054:
055: /** Don't fire events when text is set directly (to conform to regular
056: JTextArea behavior). */
057: public void setText(String text) {
058: fieldChanging = true;
059: super .setText(text);
060: fieldChanging = false;
061: }
062:
063: /** Detect temporary focus loss due to menu activation. */
064: private boolean isLocalMenuActive() {
065: boolean active = false;
066: Window window = SwingUtilities.getWindowAncestor(TextArea.this );
067: while (window != null && !active) {
068: window = SwingUtilities.getWindowAncestor(window);
069: if (window instanceof JFrame) {
070: Component comp = window.getFocusOwner();
071: Log.debug("Focus is in "
072: + abbot.tester.Robot.toString(comp));
073: active = comp != null && (comp instanceof JMenuItem);
074: }
075: }
076: return active;
077: }
078:
079: protected void fireActionPerformed(String actionCommand) {
080: fireActionPerformed(actionCommand, false);
081: }
082:
083: protected void fireActionPerformed() {
084: fireActionPerformed(getText(), true);
085: }
086:
087: /** On normal fire (enter) select all text. */
088: protected void fireActionPerformed(String cmd, boolean select) {
089: if (select)
090: selectAll();
091: ActionEvent e = new ActionEvent(this ,
092: ActionEvent.ACTION_PERFORMED, cmd);
093: Iterator iter = listeners.iterator();
094: while (iter.hasNext()) {
095: ((ActionListener) iter.next()).actionPerformed(e);
096: }
097: }
098:
099: public void addActionListener(ActionListener l) {
100: listeners.add(l);
101: }
102:
103: public void removeActionListener(ActionListener l) {
104: listeners.remove(l);
105: }
106: }
|