|
View:
New views
4 Messages
—
Rating Filter:
Alert me
|
|
|
wrote a class, sharing itHello,
After using GlazedLists for some time, which is a really nice project, I wanted to share some class I wrote. For filters which need to change Matcher frequently, you typically write a MatcherEditor. The problem is, if you have a list of employees and a list of clients, you'll have relatively similar MatcherEditors, which just install an Employee Matcher or a Client Matcher. I wrote this class, DynamicMatcherEditor, which simply takes a matcher and install it. It can also create a Matcher from a TextFilterator and a JTextComponent (and install the needed DocumentListener), which is similar to TextComponentMatcherEditor but lets you change your TextFilterator dynamically, without having to instanciating a new TextComponentMatcherEditor. So, here it is. Hope someone will check the usefullness, comment it, etc. I tried to document it enough to be quite usable. /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package be.ucl.invrech.client; import ca.odell.glazedlists.TextFilterator; import ca.odell.glazedlists.impl.matchers.TrueMatcher; import ca.odell.glazedlists.matchers.Matcher; import ca.odell.glazedlists.matchers.MatcherEditor; import ca.odell.glazedlists.matchers.MatcherEditor.Listener; import java.util.ArrayList; import java.util.List; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.JTextComponent; /** * Creates a MatcherEditor which can accept a given new Matcher anytime. * Can also create a Matcher from a JTextComponent and a TextFilterator * @author Yannick Majoros * @param T Type of the elements to match */ public class DynamicMatcherEditor<T> implements MatcherEditor<T> { private final List<Listener<T>> listeners = new ArrayList<Listener<T>>(); private Matcher<T> matcher; private DynamicMatcherEditor.TextComponentListener textComponentListener; /** * Creates a new DynamicMatcherEditor which initially matches everything */ public DynamicMatcherEditor() { this.matcher = new TrueMatcher<T>(); } /** * Creates this MatcherEditor with the specified Matcher set up as initial * Matcher * @param matcher */ public DynamicMatcherEditor(Matcher<T> matcher) { this.matcher = matcher; } /*** * Creates a matcher from a TextFilterator and a JTextComponent, which filters * entries matching the text component's document * @param textComponent * @param textFilterator */ public void setupTextFilter(JTextComponent textComponent, TextFilterator<T> textFilterator) { unregisterTextComponentListener(); textComponentListener = new TextComponentListener(textComponent, textFilterator); registerTextComponentListener(); } /*** * Dispose the component, releasing all registered listeners */ public void dispose() { unregisterTextComponentListener(); } /** * Set the given Matcher for this MatcherEditor and notify all listeners * @param matcher */ public void setMatcher(Matcher<T> matcher) { this.matcher = matcher; Event<T> event = new Event(this, Event.CHANGED, matcher); for (Listener<T> listener : listeners) { listener.changedMatcher(event); } } @Override public void addMatcherEditorListener(Listener<T> listener) { listeners.add(listener); } @Override public void removeMatcherEditorListener(Listener<T> listener) { listeners.remove(listener); } /*** * Get the current Matcher * @return */ @Override public Matcher<T> getMatcher() { return matcher; } private static class TextMatcher<T> implements Matcher<T> { private String[] searchStrings; private TextFilterator<T> textFilterator; public TextMatcher(String[] textFilters, TextFilterator<T> textFilterator) { this.searchStrings = textFilters; this.textFilterator = textFilterator; } @Override public boolean matches(T item) { List<String> baseList = new ArrayList<String>(); textFilterator.getFilterStrings(baseList, item); boolean match; for (String searchString : searchStrings) { match = false; String trimmedLowerSearchString = searchString.trim().toLowerCase(); for (String baseString : baseList) { if (baseString != null && baseString.trim().toLowerCase().contains(trimmedLowerSearchString)) { match = true; break; } } // search term not found in baseList? if (!match) { return false; } } return true; } } synchronized private void registerTextComponentListener() { JTextComponent textComponent = textComponentListener.textComponent; textComponent.getDocument().addDocumentListener(textComponentListener); } synchronized private void unregisterTextComponentListener() { if (textComponentListener == null) { return; } JTextComponent textComponent = textComponentListener.textComponent; textComponent.getDocument().removeDocumentListener(textComponentListener); textComponentListener = null; } private class TextComponentListener implements DocumentListener { private final TextFilterator<T> textFilterator; private JTextComponent textComponent; public TextComponentListener(JTextComponent textComponent, TextFilterator<T> textFilterator) { this.textComponent = textComponent; this.textFilterator = textFilterator; textChanged(); } @Override public void insertUpdate(DocumentEvent e) { textChanged(); } @Override public void removeUpdate(DocumentEvent e) { textChanged(); } @Override public void changedUpdate(DocumentEvent e) { textChanged(); } private void textChanged() { String[] searchStrings = textComponent.getText().split("[ \t]"); setMatcher(new TextMatcher(searchStrings, textFilterator)); } } } |
|
|
Re: wrote a class, sharing itWell, nobody interested? Should I share further code?
|
|
|
Re: wrote a class, sharing itYannick,
To be honest, I'm not really "getting" the benefit of your class. Here are the two observations I have. Perhaps you can give me more information. 1) Your String search is actually much slower than the one in stock Glazed Lists. calls to trim() and toLowerCase() are going to kill performance with the number of intermediate, throwaway objects that are created. Consider using one of the TextSearchStrategies already present in GL which implement much faster String-matching algorithms (Boyer-Moore). 2) I haven't encountered a case where I needed to dynamically change the TextFilterator. Can you describe that use case more? Specifically, this part of your explanation confused me: "The problem is, if you have a list of employees and a list of clients, you'll have relatively similar MatcherEditors, which just install an Employee Matcher or a Client Matcher." 3) a public version of setMatcher() seems out of place on a MatcherEditor. Typically the MatcherEditor itself is the only source of Matchers, some external code to the MatcherEditor shouldn't "tell it" what Matcher to use. If they want to prompt a change, they should do something like change the Document behind the JTextComponent and let the normal course of actions take place (MatcherEvent is created and broadcast) Thanks, James On Nov 21, 2007 1:11 AM, ymajoros <yannick.majoros@...> wrote:
|
|
|
Re: wrote a class, sharing it
|
| Free embeddable forum powered by Nabble | Forum Help |