Home > Filter, Quick Search > Recipe 14: How to add a Quick Filter

Recipe 14: How to add a Quick Filter

Problem: How can I display a Quick Filter button with a Quick Filter text field to filter my OutlineView?

Solution:  In Recipe 9 we showed how to create a QuickFilter in order to filter an OutlineView. NetBeans RCP allows you to create a graphical filter text field in order to filter your OutlineView dynamically based on what you are typing (display the Notifications window by clicking on menu Window | IDE Tools | Notifications for an example — you need to have NetBeans version 7.3 or later).

notifications

In the class that contains your TopComponent or your panel you need to define the following:

/** Quick Search filter */
private final QuickSearch quickSearch;
/** Callback */
private final QuickSearch.Callback quickFilterCallback = new QuickFilterCallback();

and in the constructor (you need to create an empty JPanel — here called pnlQuickSearchFilter — that will host the quick filter text box):

GridBagConstraints searchConstrains = new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0);
quickSearch = QuickSearch.attach(pnlQuickSearchFilter, searchConstrains, quickFilterCallback, true);
FilterRepository.getInstance().addPropertyChangeListener(pcl);
setSearchVisible(Settings.isSearchVisible());

QuickFilterCallback is called when the user types something in the quick filter text field:

private class QuickFilterCallback implements QuickSearch.Callback {

    @Override
    public void quickSearchUpdate(String searchText) {
        FilterRepository.getInstance().setQuickSearchFilter(searchText);
        if (quickSearch != null && !quickSearch.isAlwaysShown()) {
            setSearchVisible(true);
        }
    }

    @Override
    public void showNextSelection(boolean forward) {
    }

    @Override
    public String findMaxPrefix(String prefix) {
        return prefix;
    }

    @Override
    public void quickSearchConfirmed() {
    }

    @Override
    public void quickSearchCanceled() {
        FilterRepository.getInstance().setQuickSearchFilter(null);
    }
}

FilterRepository handles the quick filter:

package org.netbeans.filters.filter.checklist;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public final class FilterRepository {

    /** Property when a new quick filter is applied. */
    public static final String PROP_QUICK_FILTER = "QUICK-FILTER";
    /** Observable. */
    private PropertyChangeSupport pcs = null;
    /** A quick search filter. */
    private String quickSearchFilter;

    /** Constructor, default. */
    private FilterRepository() {
    }

    /**
     * Singleton.
     *
     * @return the single instance of this class.
     */
    public static FilterRepository getInstance() {
        return SingletonHolder.INSTANCE;
    }

    /** SingletonHolder. */
    private static final class SingletonHolder {

        /** The only INSTANCE. */
        private static final FilterRepository INSTANCE = new FilterRepository();

        /** Private. */
        private SingletonHolder() {
        }
    }

    /**
     * @return a thread-safe PropertyChangeSupport
     */
    private PropertyChangeSupport getPropertyChangeSupport() {
        if (pcs == null) {
            pcs = new PropertyChangeSupport(this);
        }
        return pcs;
    }

    public void addPropertyChangeListener(PropertyChangeListener pcl) {
        getPropertyChangeSupport().addPropertyChangeListener(pcl);
    }

    public void removePropertyChangeListener(PropertyChangeListener pcl) {
        getPropertyChangeSupport().removePropertyChangeListener(pcl);
    }

    public void addPropertyChangeListener(String name, PropertyChangeListener pcl) {
        getPropertyChangeSupport().addPropertyChangeListener(name, pcl);
    }

    public void removePropertyChangeListener(String name, PropertyChangeListener pcl) {
        getPropertyChangeSupport().removePropertyChangeListener(name, pcl);
    }

    /**
     * Quick search filter is used by bottom panel.
     *
     * @param searchText
     * text to filter
     */
    public void setQuickSearchFilter(String searchText) {
        String oldFilter = quickSearchFilter;
        quickSearchFilter = (searchText == null || searchText.isEmpty()) ? null : searchText;
        getPropertyChangeSupport().firePropertyChange(PROP_QUICK_FILTER, oldFilter, quickSearchFilter);
    }

    public boolean isQuickSearchFilter() {
        return quickSearchFilter != null;
    }

    public String getQuickSearchFilter() {
        return quickSearchFilter;
    }
}

Settings class (copied from NetBeans source code):

import java.util.prefs.Preferences;
import org.openide.util.NbPreferences;

/**
 * @author jpeska
 */
public class Settings {

   private static final String SEARCH_VISIBLE = "searchVisible"; //NOI18N
   private static final boolean DEFAULT_SEARCH_VISIBLE = true;

   private Settings() {
   }

   public static boolean isSearchVisible() {
      return getPreferences().getBoolean(SEARCH_VISIBLE, DEFAULT_SEARCH_VISIBLE);
   }

   public static void setSearchVisible(boolean searchVisible) {
      getPreferences().putBoolean(SEARCH_VISIBLE, searchVisible);
   }

   private static Preferences getPreferences() {
      return NbPreferences.forModule(Settings.class);
   }
}

setSearchVisible() method does the actual filtering of the OutlineView using the setQuickFilter() and unsetQuickFilter() methods explained in Recipe 9.

    /**
     * @param visible if {@code true} then display the quick search panel
     */
    public void setSearchVisible(boolean visible) {
        quickSearch.setAlwaysShown(visible);
        if (!visible) {
            unsetQuickFilter();
        } else if (FilterRepository.getInstance().isQuickSearchFilter()) {
            setQuickFilter(0, getQuickFilter(FilterRepository.getInstance().getQuickSearchFilter()));
        }
        Settings.setSearchVisible(visible);
    }

    /**
     * Create a QuickFilter from the given String.
     *
     * @param qsFilter filter as String
     * @return a QuickFilter from the given String
     */
    private QuickFilter getQuickFilter(String qsFilter) {
        return (Object aValue) -> {
            if (aValue instanceof TaskNode) {
                Task task = ((TaskNode) aValue).getLookup().lookup(Task.class);
                return task.getDescription().contains(qsFilter)
                        || String.valueOf(task.getPriority()).contains(qsFilter)
                        || task.getDueDate().toString().contains(qsFilter);
            } else {
                return false;
            }
        };
    }

In the above example we show how to filter an OutlineView that contains TaskNodes. The filter is trying to match the Task‘s description, priority or due date.

The last remaining change is the property change listener which listens to changes in FilterRepository.

    /** Listen to changes in the FilterRepository and filter the outline view
     * accordingly. */
    private final PropertyChangeListener pcl = (final PropertyChangeEvent evt) -> {
        SwingUtilities.invokeLater(() -> {
            // filter outline view on QuickSearchFilter input
            if (FilterRepository.PROP_QUICK_FILTER.equals(evt.getPropertyName())) {
                final String newQuickSearchFilter = (String) evt.getNewValue();
                if (newQuickSearchFilter != null && !newQuickSearchFilter.isEmpty()) {
                    unsetQuickFilter();   // should run in EDT
                    if (!newQuickSearchFilter.isEmpty()) { // should run in EDT
                        setQuickFilter(0, getQuickFilter(newQuickSearchFilter));
                    }
                } else {
                    unsetQuickFilter();  // should run in EDT
                }
            }
        });
    };
Advertisements
Categories: Filter, Quick Search
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: