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