Author: kmorin Date: 2013-02-26 16:04:07 +0100 (Tue, 26 Feb 2013) New Revision: 2572 Url: http://nuiton.org/projects/jaxx/repository/revisions/2572 Log: fixes #2535 Add filter and sorted on the BeanDoubleList widget Added: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/renderer/FilteredDecoratorListCellRenderer.java Modified: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/model/JaxxFilterableListModel.java Modified: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/model/JaxxFilterableListModel.java =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/model/JaxxFilterableListModel.java 2013-02-25 14:51:57 UTC (rev 2571) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/model/JaxxFilterableListModel.java 2013-02-26 15:04:07 UTC (rev 2572) @@ -1,25 +1,33 @@ package jaxx.runtime.swing.model; +import com.google.common.base.Predicate; +import com.google.common.collect.Lists; import java.util.ArrayList; import java.util.Collection; +import java.util.List; +import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; import org.nuiton.util.decorator.JXPathDecorator; /** + * List model for filterable lists. * * @author kmorin <kmorin@codelutin.com> + * @since 2.5.11 */ public class JaxxFilterableListModel<E> extends JaxxDefaultListModel<E> { private static final long serialVersionUID = 1L; - private ArrayList<E> filteredItems = new ArrayList<E>(); + protected ArrayList<E> filteredItems = Lists.newArrayList(); protected String filterText; /** the decorator of data */ protected JXPathDecorator<E> decorator; + protected List<Predicate<E>> filters = Lists.newArrayList(); + @Override public E getElementAt(int index) { if (index < filteredItems.size()) { @@ -72,7 +80,7 @@ @Override public void setSize(int newSize) { super.setSize(newSize); - ensureCapacity(newSize); + filteredItems.ensureCapacity(newSize); } @Override @@ -160,17 +168,49 @@ this.decorator = decorator; } + public void addFilter(Predicate<E> filter) { + filters.add(filter); + refilter(); + } + + public void removeFilter(Predicate<E> filter) { + filters.remove(filter); + refilter(); + } + + public void clearFilters() { + filters.clear(); + refilter(); + } + protected void refilter() { filteredItems.clear(); - if (StringUtils.isBlank(filterText)) { + if (StringUtils.isBlank(filterText) && filters.isEmpty()) { filteredItems.addAll(delegate); } else { int itemNumber = delegate.size(); + Pattern pattern = null; + if (!StringUtils.isBlank(filterText)) { + String patternText = filterText.replace("*", ".*") + ".*"; + pattern = Pattern.compile(patternText, Pattern.CASE_INSENSITIVE); + } for (int i = 0 ; i < itemNumber ; i++) { E element = delegate.get(i); - if (StringUtils.startsWithIgnoreCase(decorator.toString(element), filterText)) { + boolean addElement = true; + for (Predicate<E> filter : filters) { + addElement &= filter.apply(element); + } + String decoratedElement; + if (decorator != null) { + decoratedElement = decorator.toString(element); + } else { + decoratedElement = String.valueOf(element); + } + boolean matches = pattern == null + || pattern.matcher(decoratedElement).matches(); + if (matches && addElement) { filteredItems.add(element); } } Copied: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/renderer/FilteredDecoratorListCellRenderer.java (from rev 2567, trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/renderer/DecoratorListCellRenderer.java) =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/renderer/FilteredDecoratorListCellRenderer.java (rev 0) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/renderer/FilteredDecoratorListCellRenderer.java 2013-02-26 15:04:07 UTC (rev 2572) @@ -0,0 +1,104 @@ +/* + * #%L + * JAXX :: Runtime + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2008 - 2010 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package jaxx.runtime.swing.renderer; + +import java.awt.Component; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.swing.JList; +import javax.swing.ListCellRenderer; +import org.nuiton.util.decorator.Decorator; + +/** + * A {@link ListCellRenderer} which compute text with the given {@link #decorator}, + * highlights a part of the rendered text, + * and leave the hand to the {@link #delegate} to perform the visual renderer. + * + * @author kmorin <kmorin@codelutin.com> + * @since 2.5.11 + */ +public class FilteredDecoratorListCellRenderer extends DecoratorListCellRenderer { + + /** text to highlight */ + protected String filterText; + + public FilteredDecoratorListCellRenderer(Decorator<?> decorator) { + super(decorator); + } + + public FilteredDecoratorListCellRenderer(ListCellRenderer delegate, + Decorator<?> decorator) { + super(delegate, decorator); + } + + public String getFilterText() { + return filterText; + } + + public void setFilterText(String filterText) { + this.filterText = filterText; + } + + @Override + public Component getListCellRendererComponent(JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) { + + if (!(value instanceof String) && decorator != null) { + value = decorator.toString(value); + } + + String stringValue = String.valueOf(value); + if (filterText != null) { + // add the groups in the pattern + String patternText = "(" + filterText.replace("*", ").*(") + ").*"; + Pattern pattern = Pattern.compile(patternText, Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(stringValue); + + if (matcher.find()) { + // for each group caught, add the text between the previous group + // and the current group and surround the group with the highlighter + String s = ""; + int i = 0; + for (int g = 1 ; g <= matcher.groupCount() ; g++) { + String match = matcher.group(g); + int indexOfMatch = stringValue.indexOf(match, i); + s += stringValue.substring(i, indexOfMatch) + "<em style='background:#FFFF00'>" + match + "</em>"; + i = indexOfMatch + match.length(); + } + s += stringValue.substring(i); + stringValue = "<html>" + s + "</html>"; + } + } + return delegate.getListCellRendererComponent(list, + stringValue, + index, + isSelected, + cellHasFocus + ); + } +}
participants (1)
-
kmorin@users.nuiton.org