|
|
@@ -0,0 +1,83 @@
|
|
|
+package org.leumasjaffe.event;
|
|
|
+
|
|
|
+import java.beans.PropertyChangeEvent;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.function.Consumer;
|
|
|
+
|
|
|
+import javax.swing.SwingUtilities;
|
|
|
+import javax.swing.event.ChangeEvent;
|
|
|
+import javax.swing.event.ChangeListener;
|
|
|
+import javax.swing.event.DocumentEvent;
|
|
|
+import javax.swing.event.DocumentListener;
|
|
|
+import javax.swing.text.Document;
|
|
|
+import javax.swing.text.JTextComponent;
|
|
|
+
|
|
|
+@FunctionalInterface
|
|
|
+public interface AnyActionDocumentListener extends DocumentListener {
|
|
|
+
|
|
|
+ public void update(DocumentEvent e);
|
|
|
+
|
|
|
+ public default void insertUpdate(DocumentEvent e) { this.update(e); }
|
|
|
+ public default void removeUpdate(DocumentEvent e) { this.update(e); }
|
|
|
+ public default void changedUpdate(DocumentEvent e) { this.update(e); }
|
|
|
+
|
|
|
+ public static void skipEmpty(final JTextComponent text,
|
|
|
+ final Consumer<ChangeEvent> in) {
|
|
|
+ addChangeListener(text, e -> {
|
|
|
+ if (text.getText().trim().isEmpty()) { return; }
|
|
|
+ in.accept(e);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void emptyOrText(final JTextComponent text,
|
|
|
+ final Consumer<ChangeEvent> empty,
|
|
|
+ final Consumer<ChangeEvent> in) {
|
|
|
+ addChangeListener(text, e -> {
|
|
|
+ if (text.getText().trim().isEmpty()) { empty.accept(e); }
|
|
|
+ else { in.accept(e); }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Installs a listener to receive notification when the text of any
|
|
|
+ * {@code JTextComponent} is changed. Internally, it installs a
|
|
|
+ * {@link DocumentListener} on the text component's {@link Document},
|
|
|
+ * and a {@link PropertyChangeListener} on the text component to detect
|
|
|
+ * if the {@code Document} itself is replaced.
|
|
|
+ *
|
|
|
+ * @param text any text component, such as a {@link JTextField}
|
|
|
+ * or {@link JTextArea}
|
|
|
+ * @param changeListener a listener to receieve {@link ChangeEvent}s
|
|
|
+ * when the text is changed; the source object for the events
|
|
|
+ * will be the text component
|
|
|
+ * @throws NullPointerException if either parameter is null
|
|
|
+ */
|
|
|
+ public static void addChangeListener(final JTextComponent text,
|
|
|
+ final ChangeListener changeListener) {
|
|
|
+ Objects.requireNonNull(text);
|
|
|
+ Objects.requireNonNull(changeListener);
|
|
|
+ final DocumentListener dl = new AnyActionDocumentListener() {
|
|
|
+ private int lastChange = 0, lastNotifiedChange = 0;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void update(DocumentEvent e) {
|
|
|
+ lastChange++;
|
|
|
+ SwingUtilities.invokeLater(() -> {
|
|
|
+ if (lastNotifiedChange != lastChange) {
|
|
|
+ lastNotifiedChange = lastChange;
|
|
|
+ changeListener.stateChanged(new ChangeEvent(text));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ };
|
|
|
+ text.addPropertyChangeListener("document", (PropertyChangeEvent e) -> {
|
|
|
+ Document d1 = (Document)e.getOldValue();
|
|
|
+ Document d2 = (Document)e.getNewValue();
|
|
|
+ if (d1 != null) d1.removeDocumentListener(dl);
|
|
|
+ if (d2 != null) d2.addDocumentListener(dl);
|
|
|
+ dl.changedUpdate(null);
|
|
|
+ });
|
|
|
+ Document d = text.getDocument();
|
|
|
+ if (d != null) d.addDocumentListener(dl);
|
|
|
+ }
|
|
|
+}
|