001/*
002 * $Id: JXSearchPanel.java 4158 2012-02-03 18:29:40Z kschaefe $
003 *
004 * Copyright 2004 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 */
021
022package org.jdesktop.swingx;
023
024import java.util.ArrayList;
025import java.util.HashMap;
026import java.util.Iterator;
027import java.util.List;
028import java.util.Locale;
029import java.util.Map;
030import java.util.regex.Pattern;
031
032import javax.swing.ComboBoxModel;
033import javax.swing.DefaultComboBoxModel;
034
035import org.jdesktop.beans.JavaBean;
036import org.jdesktop.swingx.decorator.Highlighter;
037import org.jdesktop.swingx.renderer.DefaultListRenderer;
038import org.jdesktop.swingx.renderer.LocalizableStringValue;
039import org.jdesktop.swingx.renderer.StringValue;
040import org.jdesktop.swingx.search.PatternMatcher;
041import org.jdesktop.swingx.search.PatternModel;
042/**
043 * <p>
044 * {@code JXSearchPanel} provides complex searching features. Users are able to
045 * specify searching rules, enter searching text (including regular
046 * expressions), and toggle case-sensitivity.
047 * </p>
048 * <p>
049 * One of the main features that {@code JXSearchPanel} provides is the ability
050 * to update {@link PatternMatcher}s. To highlight text with a
051 * {@link Highlighter}, you need to update the highlighter via a pattern
052 * matcher.
053 * </p>
054 * <pre>
055 * public class PatternHandler implements PatternMatcher {
056 * 
057 *     private Highlighter highlighter;
058 * 
059 *     private Pattern pattern;
060 * 
061 *     public void setPattern(Pattern pattern) {
062 *         this.pattern = pattern;
063 *         highlighter.setHighlightPredicate(new PatternPredicate(pattern));
064 *     }
065 * 
066 * }
067 * </pre>
068 * <p>
069 * TODO: allow custom PatternModel and/or access to configuration of bound
070 * PatternModel.
071 * </p>
072 * <p>
073 * TODO: fully support control of multiple PatternMatchers.
074 * </p>
075 * 
076 * @author Ramesh Gupta
077 * @author Jeanette Winzenburg
078 */
079@JavaBean
080public class JXSearchPanel extends AbstractPatternPanel {
081    /**
082     * The action command key.
083     */
084    public static final String MATCH_RULE_ACTION_COMMAND = "selectMatchRule";
085
086    private JXComboBox searchCriteria;
087
088    private List<PatternMatcher> patternMatchers;
089    
090
091    /**
092     * Creates a search panel.
093     */
094    public JXSearchPanel() {
095        initComponents();
096        build();
097        initActions();
098        bind();
099        getPatternModel().setIncremental(true);
100    }
101
102//----------------- accessing public properties
103
104    /**
105     * Adds a pattern matcher.
106     * 
107     * @param matcher
108     *            the matcher to add.
109     */
110    public void addPatternMatcher(PatternMatcher matcher) {
111        getPatternMatchers().add(matcher);
112        updateFieldName(matcher);
113    }
114    
115    /**
116     * sets the PatternFilter control.
117     * 
118     * PENDING: change to do a addPatternMatcher to enable multiple control.
119     * 
120     */
121//    public void setPatternFilter(PatternFilter filter) {
122//        getPatternMatchers().add(filter);
123//        updateFieldName(filter);
124//    }
125
126    /**
127     * set the label of the search combo.
128     * 
129     * @param name
130     *            the label
131     */
132    public void setFieldName(String name) {
133        String old = searchLabel.getText();
134        searchLabel.setText(name);
135        firePropertyChange("fieldName", old, searchLabel.getText());
136    }
137
138    /**
139     * returns the label of the search combo.
140     * 
141     */
142    public String getFieldName() {
143        return searchLabel.getText();
144    }
145
146    /**
147     * returns the current compiled Pattern.
148     * 
149     * @return the current compiled <code>Pattern</code>
150     */
151    public Pattern getPattern() {
152        return patternModel.getPattern();
153    }
154
155    /**
156     * @param matcher
157     */
158    protected void updateFieldName(PatternMatcher matcher) {
159        
160//        if (matcher instanceof PatternFilter) {
161//            PatternFilter filter = (PatternFilter) matcher;
162//            searchLabel.setText(filter.getColumnName());
163//        } else {
164            if (searchLabel.getText().length() == 0) { // ugly hack
165                searchLabel.setText("Field");
166                /** TODO: Remove this hack!!! */
167//            }
168        }
169    }
170
171    // ---------------- action callbacks
172
173    /**
174     * Updates the pattern matchers.
175     */
176    @Override
177    public void match() {
178        for (Iterator<PatternMatcher> iter = getPatternMatchers().iterator(); iter.hasNext();) {
179            iter.next().setPattern(getPattern());
180            
181        }
182    }
183
184    /**
185     * set's the PatternModel's MatchRule to the selected in combo. 
186     * 
187     * NOTE: this
188     * is public as an implementation side-effect! 
189     * No need to ever call directly.
190     */
191    public void updateMatchRule() {
192        getPatternModel().setMatchRule(
193                (String) searchCriteria.getSelectedItem());
194    }
195
196    private List<PatternMatcher> getPatternMatchers() {
197        if (patternMatchers == null) {
198            patternMatchers = new ArrayList<PatternMatcher>();
199        }
200        return patternMatchers;
201    }
202
203    //---------------- init actions and model
204    
205    @Override
206    protected void initExecutables() {
207        super.initExecutables();
208        getActionMap().put(MATCH_RULE_ACTION_COMMAND,
209                createBoundAction(MATCH_RULE_ACTION_COMMAND, "updateMatchRule"));
210    }
211
212
213    //--------------------- binding support
214    
215
216
217    /**
218     * bind the components to the patternModel/actions.
219     */
220    @Override
221    protected void bind() {
222        super.bind();
223        List<?> matchRules = getPatternModel().getMatchRules();
224        // PENDING: map rules to localized strings
225        ComboBoxModel model = new DefaultComboBoxModel(matchRules.toArray());
226        model.setSelectedItem(getPatternModel().getMatchRule());
227        searchCriteria.setModel(model);
228        searchCriteria.setAction(getAction(MATCH_RULE_ACTION_COMMAND));
229        searchCriteria.setRenderer(new DefaultListRenderer(createStringValue(getLocale())));
230        
231    }
232
233    
234    private StringValue createStringValue(Locale locale) {
235        // TODO Auto-generated method stub
236        Map<Object, String> keys = new HashMap<Object, String>();
237        keys.put(PatternModel.MATCH_RULE_CONTAINS, 
238                PatternModel.MATCH_RULE_CONTAINS);
239        keys.put(PatternModel.MATCH_RULE_ENDSWITH, 
240                PatternModel.MATCH_RULE_ENDSWITH);
241        keys.put(PatternModel.MATCH_RULE_EQUALS, 
242                PatternModel.MATCH_RULE_EQUALS);
243        keys.put(PatternModel.MATCH_RULE_STARTSWITH, 
244                PatternModel.MATCH_RULE_STARTSWITH);
245        return new LocalizableStringValue(keys, PatternModel.SEARCH_PREFIX, locale);
246    }
247
248    /**
249     * {@inheritDoc}
250     */
251    @Override
252    protected void updateLocaleState(Locale locale) {
253        // TODO Auto-generated method stub
254        super.updateLocaleState(locale);
255        searchCriteria.setRenderer(new DefaultListRenderer(createStringValue(locale)));
256    }
257
258    //------------------------ init ui
259    /**
260     * build container by adding all components.
261     * PRE: all components created.
262     */
263    private void build() {
264        add(searchLabel);
265        add(searchCriteria);
266        add(searchField);
267        add(matchCheck);
268    }
269
270    /**
271     * create contained components.
272     * 
273     *
274     */
275    @Override
276    protected void initComponents() {
277        super.initComponents();
278        searchCriteria = new JXComboBox();
279    }
280
281
282}