001/* 002 * $Id: PatternPredicate.java 3927 2011-02-22 16:34:11Z kleopatra $ 003 * 004 * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021package org.jdesktop.swingx.decorator; 022 023import java.awt.Component; 024import java.util.regex.Pattern; 025 026/** 027 * Pattern based HighlightPredicate. <p> 028 * 029 * Turns on the highlight of a single or all columns of the current row if 030 * a match of the String representation of cell content against the given Pattern 031 * is found.<p> 032 * 033 * The match logic can be configured to either test 034 * one specific column in the current row or all columns. In the latter case 035 * the logic is the same as in RowFilters.GeneralFilter: the row is included 036 * if any of the cell contents in the row are matches. <p> 037 * 038 * 039 * @author Jeanette Winzenburg 040 */ 041public class PatternPredicate implements HighlightPredicate { 042 public static final int ALL = -1; 043 044 private int highlightColumn; 045 private int testColumn; 046 private Pattern pattern; 047 048 /** 049 * Instantiates a Predicate with the given Pattern and testColumn index 050 * (in model coordinates) highlighting all columns. 051 * A column index of -1 is interpreted 052 * as "all". 053 * 054 * @param pattern the Pattern to test the cell value against 055 * @param testColumn the column index in model coordinates 056 * of the cell which contains the value to test against the pattern 057 */ 058 public PatternPredicate(Pattern pattern, int testColumn) { 059 this(pattern, testColumn, ALL); 060 } 061 062 /** 063 * Instantiates a Predicate with the given Pattern testing against 064 * all columns and highlighting all columns. 065 * 066 * @param pattern the Pattern to test the cell value against 067 */ 068 public PatternPredicate(Pattern pattern) { 069 this(pattern, ALL, ALL); 070 } 071 072 /** 073 * Instantiates a Predicate with the given Pattern and test-/decorate 074 * column index in model coordinates. A column index of -1 is interpreted 075 * as "all". 076 * 077 * 078 * @param pattern the Pattern to test the cell value against 079 * @param testColumn the column index in model coordinates 080 * of the cell which contains the value 081 * to test against the pattern 082 * @param decorateColumn the column index in model coordinates 083 * of the cell which should be 084 * decorated if the test against the value succeeds. 085 */ 086 public PatternPredicate(Pattern pattern, int testColumn, int decorateColumn) { 087 this.pattern = pattern; 088 this.testColumn = testColumn; 089 this.highlightColumn = decorateColumn; 090 } 091 092 /** 093 * Instantiates a Predicate with the given Pattern testing against 094 * all columns and highlighting all columns. 095 * 096 * @param pattern the Pattern to test the cell value against 097 */ 098 public PatternPredicate(String pattern) { 099 this(pattern, ALL, ALL); 100 } 101 102 /** 103 * Instantiates a Predicate with the given regex and test 104 * column index in model coordinates. The pattern string is compiled to a 105 * Pattern with flags 0. A column index of -1 is interpreted 106 * as "all". 107 * 108 * @param regex the regex string to test the cell value against 109 * @param testColumn the column index in model coordinates 110 * of the cell which contains the value 111 * to test against the pattern 112 */ 113 public PatternPredicate(String regex, int testColumn) { 114 this(regex, testColumn, ALL); 115 } 116 117 118 /** 119 * Instantiates a Predicate with the given regex and test-/decorate 120 * column index in model coordinates. The pattern string is compiled to a 121 * Pattern with flags 0. A column index of -1 is interpreted 122 * as "all". 123 * 124 * @param regex the regex string to test the cell value against 125 * @param testColumn the column index in model coordinates 126 * of the cell which contains the value 127 * to test against the pattern 128 * @param decorateColumn the column index in model coordinates 129 * of the cell which should be 130 * decorated if the test against the value succeeds. 131 */ 132 public PatternPredicate(String regex, int testColumn, int decorateColumn) { 133 this(Pattern.compile(regex), testColumn, decorateColumn); 134 } 135 136 /** 137 * 138 * @inherited <p> 139 * 140 * Implemented to return true if the match of cell content's String representation 141 * against the Pattern if found and the adapter's view column maps to the 142 * decorateColumn/s. Otherwise returns false. 143 * 144 */ 145 @Override 146 public boolean isHighlighted(Component renderer, ComponentAdapter adapter) { 147 if (isHighlightCandidate(adapter)) { 148 return test(adapter); 149 } 150 return false; 151 } 152 153 /** 154 * Test the value. This is called only if the 155 * pre-check returned true, because accessing the 156 * value might be potentially costly 157 * @param adapter 158 * @return 159 */ 160 private boolean test(ComponentAdapter adapter) { 161 // single test column 162 if (testColumn >= 0) return testColumn(adapter, testColumn); 163 // test all 164 for (int column = 0; column < adapter.getColumnCount(); column++) { 165 boolean result = testColumn(adapter, column); 166 if (result) return true; 167 } 168 return false; 169 } 170 171 /** 172 * @param adapter 173 * @param testColumn 174 * @return 175 */ 176 private boolean testColumn(ComponentAdapter adapter, int testColumn) { 177 if (!adapter.isTestable(testColumn)) 178 return false; 179 String value = adapter.getString(testColumn); 180 181 if ((value == null) || (value.length() == 0)) { 182 return false; 183 } 184 return pattern.matcher(value).find(); 185 } 186 187 /** 188 * A quick pre-check. 189 * @param adapter 190 * 191 * @return 192 */ 193 private boolean isHighlightCandidate(ComponentAdapter adapter) { 194 return (pattern != null) && 195 ((highlightColumn < 0) || 196 (highlightColumn == adapter.convertColumnIndexToModel(adapter.column))); 197 } 198 199 /** 200 * 201 * @return returns the column index to decorate (in model coordinates) 202 */ 203 public int getHighlightColumn() { 204 return highlightColumn; 205 } 206 207 /** 208 * 209 * @return returns the Pattern to test the cell value against 210 */ 211 public Pattern getPattern() { 212 return pattern; 213 } 214 215 /** 216 * 217 * @return the column to use for testing (in model coordinates) 218 */ 219 public int getTestColumn() { 220 return testColumn; 221 } 222 223}