Created
January 14, 2022 03:28
-
-
Save RustyKnight/6c93b97c49ade0f3e0d146dab0fb9159 to your computer and use it in GitHub Desktop.
A DocumentFilter which allows filters to be chained together
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.Component; | |
import java.awt.KeyboardFocusManager; | |
import java.awt.Toolkit; | |
import javax.swing.LookAndFeel; | |
import javax.swing.UIManager; | |
import javax.swing.text.AbstractDocument; | |
import javax.swing.text.AttributeSet; | |
import javax.swing.text.BadLocationException; | |
import javax.swing.text.Document; | |
import javax.swing.text.DocumentFilter; | |
import javax.swing.text.JTextComponent; | |
/** | |
* A single DocumentFilter can be set on an AbstractDocument. There may be times | |
* when you wish to perform multiple filtering of the data as it is added to a | |
* Document. By extending the ChainedDocumentFilter instead of the | |
* DocumentFilter you will receive added flexibility in that the filter can be | |
* used stand alone or with other ChainedDocumentFilters. | |
* | |
* Whenever one filter step fails, the chaining of the filters is also | |
* terminated. In this case is it recommended you invoke the | |
* provideErrorFeedback() method to provide user feedback. | |
*/ | |
// Original source https://tips4java.wordpress.com/2009/10/18/chaining-document-filters/ | |
abstract class ChainedDocumentFilter extends DocumentFilter { | |
private DocumentFilter filter; | |
/** | |
* Standard constructor for standalone usage | |
*/ | |
public ChainedDocumentFilter() { | |
this(null); | |
} | |
/** | |
* Constructor used when further filtering is required after this filter has | |
* been applied. | |
*/ | |
public ChainedDocumentFilter(DocumentFilter filter) { | |
setFilter(filter); | |
} | |
/** | |
* Get the next filter in the chain. | |
* | |
* @return the next filter in the chain | |
*/ | |
public DocumentFilter getFilter() { | |
return filter; | |
} | |
/** | |
* Set the next filter in the chain | |
* | |
* @param filter | |
*/ | |
public void setFilter(DocumentFilter filter) { | |
this.filter = filter; | |
} | |
/** | |
* Install this filter on the AbstractDocument | |
* | |
* @param components the text components that will use this filter | |
*/ | |
public void installFilter(JTextComponent... components) { | |
for (JTextComponent component : components) { | |
Document doc = component.getDocument(); | |
if (doc instanceof AbstractDocument) { | |
((AbstractDocument) doc).setDocumentFilter(this); | |
} | |
} | |
} | |
/** | |
* Remove this filter from the AbstractDocument | |
* | |
* @param compoents remove the filter from the specified text components | |
*/ | |
public void uninstallFilter(JTextComponent... components) { | |
for (JTextComponent component : components) { | |
Document doc = component.getDocument(); | |
if (doc instanceof AbstractDocument) { | |
((AbstractDocument) doc).setDocumentFilter(null); | |
} | |
} | |
} | |
/** | |
* Provide appropriate LAF feedback when a filter error occurs. | |
*/ | |
protected void provideErrorFeedback() { | |
LookAndFeel laf = UIManager.getLookAndFeel(); | |
if (laf == null) { | |
Toolkit.getDefaultToolkit().beep(); | |
} else { | |
KeyboardFocusManager fm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); | |
Component component = fm.getFocusOwner(); | |
laf.provideErrorFeedback(component); | |
} | |
} | |
@Override | |
public void insertString(DocumentFilter.FilterBypass fb, int offs, String str, AttributeSet a) | |
throws BadLocationException { | |
if (filter == null) { | |
super.insertString(fb, offs, str, a); | |
} else { | |
filter.insertString(fb, offs, str, a); | |
} | |
} | |
@Override | |
public void replace(DocumentFilter.FilterBypass fb, int offs, int length, String str, AttributeSet a) | |
throws BadLocationException { | |
if (filter == null) { | |
super.replace(fb, offs, length, str, a); | |
} else { | |
filter.replace(fb, offs, length, str, a); | |
} | |
} | |
@Override | |
public void remove(DocumentFilter.FilterBypass fb, int offset, int length) | |
throws BadLocationException { | |
if (filter == null) { | |
super.remove(fb, offset, length); | |
} else { | |
filter.remove(fb, offset, length); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment