001/*
002 * $Id: ListSearchable.java 3166 2009-01-02 13:27:18Z rah003 $
003 *
004 * Copyright 2007 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.search;
022
023import java.util.regex.Matcher;
024import java.util.regex.Pattern;
025
026import org.jdesktop.swingx.JXList;
027import org.jdesktop.swingx.decorator.AbstractHighlighter;
028import org.jdesktop.swingx.decorator.Highlighter;
029
030public class ListSearchable extends AbstractSearchable {
031
032        protected JXList list;
033
034        public ListSearchable(JXList list) {
035           this.list = list; 
036        }
037        
038        @Override
039        protected void findMatchAndUpdateState(Pattern pattern, int startRow, boolean backwards) {
040            SearchResult searchResult = null;
041            if (backwards) {
042                for (int index = startRow; index >= 0 && searchResult == null; index--) {
043                    searchResult = findMatchAt(pattern, index);
044                }
045            } else {
046                for (int index = startRow; index < getSize() && searchResult == null; index++) {
047                    searchResult = findMatchAt(pattern, index);
048                }
049            }
050            updateState(searchResult);
051        }
052
053        @Override
054        protected SearchResult findExtendedMatch(Pattern pattern, int row) {
055            
056            return findMatchAt(pattern, row);
057        }
058        /**
059         * Matches the cell content at row/col against the given Pattern.
060         * Returns an appropriate SearchResult if matching or null if no
061         * matching
062         * 
063         * @param pattern 
064         * @param row a valid row index in view coordinates
065         * @return <code>SearchResult</code> if matched otherwise null
066         */
067        protected SearchResult findMatchAt(Pattern pattern, int row) {
068            String text = list.getStringAt(row);
069            if ((text != null) && (text.length() > 0 )) {
070                Matcher matcher = pattern.matcher(text);
071                if (matcher.find()) {
072                    return createSearchResult(matcher, row, 0);
073                }
074            }
075            return null;
076        }
077        
078        /**
079         * {@inheritDoc}
080         */
081        @Override
082        protected int getSize() {
083            return list.getElementCount();
084        }
085
086        
087        /**
088         * {@inheritDoc}
089         */
090        @Override
091        public JXList getTarget() {
092            return list;
093        }
094
095        /**
096         * {@inheritDoc}
097         */
098        @Override
099        protected void moveMatchMarker() {
100            if (markByHighlighter()) {
101                moveMatchByHighlighter();
102            } else { // use selection
103                moveMatchBySelection();
104            }
105        }
106        
107        protected void moveMatchBySelection() {
108          // PENDING JW: #718-swingx - don't move selection on not found
109          // complying here is accidental, defaultListSelectionModel doesn't
110          // clear on -1 but silently does nothing
111          // isn't doc'ed anywhere - so we back out
112            if (!hasMatch()) {
113                return;
114            }
115            list.setSelectedIndex(lastSearchResult.foundRow);
116            list.ensureIndexIsVisible(lastSearchResult.foundRow);
117        }
118        
119
120        /**
121         * use and move the match highlighter.
122         * PRE: markByHighlighter
123         *
124         */
125        protected void moveMatchByHighlighter() {
126            AbstractHighlighter searchHL = getConfiguredMatchHighlighter();
127            // no match
128            if (!hasMatch()) {
129                return;
130            } else {
131                ensureInsertedSearchHighlighters(searchHL);
132                list.ensureIndexIsVisible(lastSearchResult.foundRow);
133            }
134        }
135
136
137
138        /**
139         * @param searchHighlighter
140         */
141        @Override
142        protected void removeHighlighter(Highlighter searchHighlighter) {
143            list.removeHighlighter(searchHighlighter);
144        }
145
146        /**
147         * @return all registered highlighters
148         */
149        @Override
150        protected Highlighter[] getHighlighters() {
151            return list.getHighlighters();
152        }
153
154        /**
155         * @param highlighter
156         */
157        @Override
158        protected void addHighlighter(Highlighter highlighter) {
159            list.addHighlighter(highlighter);
160        }
161
162    }