package org.limewire.ui.swing.filter; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.geom.Line2D; import java.util.ArrayList; import java.util.List; import javax.swing.Icon; import org.jdesktop.application.Resource; import org.limewire.ui.swing.util.GuiUtils; import ca.odell.glazedlists.matchers.Matcher; import ca.odell.glazedlists.matchers.MatcherEditor; /** * Base implementation of Filter that provides listener support. */ abstract class AbstractFilter<E extends FilterableItem> implements Filter<E> { /** List of listeners notified when filter is changed. */ private final List<FilterListener<E>> listenerList = new ArrayList<FilterListener<E>>(); /** Matcher/editor used to filter items. */ private final FilterMatcherEditor<E> editor; /** Resources for filters. */ private final FilterResources resources = new FilterResources(); /** Indicator that determines whether the filter is active. */ private boolean active; /** Description for active filter. */ private String activeText; /** * Constructs an AbstractFilter. */ public AbstractFilter() { // Create matcher editor for filtering. editor = new FilterMatcherEditor<E>(); } /** * Adds the specified listener to the list that is notified when the * filter changes. */ @Override public void addFilterListener(FilterListener<E> listener) { if (!listenerList.contains(listener)) { listenerList.add(listener); } } /** * Removes the specified listener from the list that is notified when the * filter changes. */ @Override public void removeFilterListener(FilterListener listener) { listenerList.remove(listener); } /** * Notifies all registered listeners that the filter has changed for the * specified filter component. */ protected void fireFilterChanged(Filter<E> filter) { for (int i = 0, size = listenerList.size(); i < size; i++) { listenerList.get(i).filterChanged(filter); } } /** * Returns an indicator that determines whether the filter is in use. */ @Override public boolean isActive() { return active; } /** * Returns the display text for an active filter. */ @Override public String getActiveText() { return activeText; } /** * Returns the matcher/editor used to filter items. */ @Override public MatcherEditor<E> getMatcherEditor() { return editor; } /** * Resets the filter. The default implementation calls * <code>deactivate()</code>. Subclasses may override this method to * update the Swing component when the filter is reset. */ @Override public void reset() { deactivate(); } /** * Activates the filter using the specified text description and matcher. */ protected void activate(String activeText, Matcher<E> matcher) { this.activeText = activeText; editor.setMatcher(matcher); active = true; } /** * Deactivates the filter by clearing the text description and matcher. */ protected void deactivate() { editor.setMatcher(null); activeText = null; active = false; } /** * Returns the resource container for the filter. */ protected FilterResources getResources() { return resources; } /** * Resource container for filters. */ public static class FilterResources { @Resource(key="AdvancedFilter.filterWidth") private int filterWidth; @Resource(key="AdvancedFilter.background") private Color background; @Resource(key="AdvancedFilter.headerColor") private Color headerColor; @Resource(key="AdvancedFilter.headerFont") private Font headerFont; @Resource(key="AdvancedFilter.highlightBackground") private Color highlightBackground; @Resource(key="AdvancedFilter.highlightForeground") private Color highlightForeground; @Resource(key="AdvancedFilter.rowColor") private Color rowColor; @Resource(key="AdvancedFilter.rowFont") private Font rowFont; @Resource(key="AdvancedFilter.popupBorderColor") private Color popupBorderColor; // TODO create icon resource private Icon popupCloseIcon = new CloseIcon(Color.WHITE, 6); @Resource(key="AdvancedFilter.popupHeaderFont") private Font popupHeaderFont; @Resource(key="AdvancedFilter.popupHeaderBackground") private Color popupHeaderBackground; @Resource(key="AdvancedFilter.popupHeaderForeground") private Color popupHeaderForeground; /** * Constructs a FilterResources object. */ FilterResources() { GuiUtils.assignResources(this); } /** * Returns the filter width. */ public int getFilterWidth() { return filterWidth; } /** * Returns the background color for the filter. */ public Color getBackground() { return background; } /** * Returns the text color for the filter header. */ public Color getHeaderColor() { return headerColor; } /** * Returns the text font for the filter header. */ public Font getHeaderFont() { return headerFont; } /** * Returns the background color for highlighted filter rows. */ public Color getHighlightBackground() { return highlightBackground; } /** * Returns the foreground color for highlighted filter rows. */ public Color getHighlightForeground() { return highlightForeground; } /** * Returns the border color for filter popup. */ public Color getPopupBorderColor() { return popupBorderColor; } /** * Returns the close icon for filter popup. */ public Icon getPopupCloseIcon() { return popupCloseIcon; } /** * Returns the header font for filter popup. */ public Font getPopupHeaderFont() { return popupHeaderFont; } /** * Returns the header background for the filter popup. */ public Color getPopupHeaderBackground() { return popupHeaderBackground; } /** * Returns the header foreground for the filter popup. */ public Color getPopupHeaderForeground() { return popupHeaderForeground; } /** * Returns the text color for filter rows. */ public Color getRowColor() { return rowColor; } /** * Returns the text font for filter rows. */ public Font getRowFont() { return rowFont; } } /** * Button icon to close filter popup. */ private static class CloseIcon implements Icon { private static final float SIZE_TO_THICKNESS = 4.0f; private final Color color; private final int size; public CloseIcon(Color color, int size) { this.color = color; this.size = size; } @Override public int getIconHeight() { return this.size; } @Override public int getIconWidth() { return this.size; } @Override public void paintIcon(Component c, Graphics g, int x, int y) { // Create graphics. Graphics2D g2d = (Graphics2D) g.create(); // Set graphics to use anti-aliasing for smoothness. g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // Set line color and thickness. float thickness = Math.max(this.size / SIZE_TO_THICKNESS, 1.0f); g2d.setColor(this.color); g2d.setStroke(new BasicStroke(thickness)); // Create shape. Shape backSlash = new Line2D.Double(0, 0, this.size, this.size); Shape slash = new Line2D.Double(0, this.size, this.size, 0); // Draw shape at specified position. g2d.translate(x, y); g2d.draw(backSlash); g2d.draw(slash); // Dispose graphics. g2d.dispose(); } } }