001    /*
002     * $Id: TreeSearchable.java 3166 2009-01-02 13:27:18Z rah003 $
003     *
004     * Copyright 2008 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    package org.jdesktop.swingx.search;
022    
023    import java.util.regex.Matcher;
024    import java.util.regex.Pattern;
025    
026    import org.jdesktop.swingx.JXTree;
027    import org.jdesktop.swingx.decorator.AbstractHighlighter;
028    import org.jdesktop.swingx.decorator.Highlighter;
029    
030    /**
031         * A searchable targetting the visible rows of a JXTree.
032         * 
033         * PENDING: value to string conversion should behave as nextMatch (?) which
034         * uses the convertValueToString().
035         * 
036         */
037        public class TreeSearchable extends AbstractSearchable {
038    
039            protected JXTree tree;
040    
041    
042            /**
043             * @param tree
044             */
045            public TreeSearchable(JXTree tree) {
046                this.tree = tree;
047            }
048    
049            @Override
050            protected void findMatchAndUpdateState(Pattern pattern, int startRow,
051                    boolean backwards) {
052                SearchResult searchResult = null;
053                if (backwards) {
054                    for (int index = startRow; index >= 0 && searchResult == null; index--) {
055                        searchResult = findMatchAt(pattern, index);
056                    }
057                } else {
058                    for (int index = startRow; index < getSize()
059                            && searchResult == null; index++) {
060                        searchResult = findMatchAt(pattern, index);
061                    }
062                }
063                updateState(searchResult);
064    
065            }
066    
067            @Override
068            protected SearchResult findExtendedMatch(Pattern pattern, int row) {
069                return findMatchAt(pattern, row);
070            }
071    
072            /**
073             * Matches the cell content at row/col against the given Pattern.
074             * Returns an appropriate SearchResult if matching or null if no
075             * matching
076             * 
077             * @param pattern
078             * @param row
079             *            a valid row index in view coordinates
080             *            a valid column index in view coordinates
081             * @return an appropriate <code>SearchResult</code> if matching or
082             * null if no matching
083             */
084            protected SearchResult findMatchAt(Pattern pattern, int row) {
085                String text = tree.getStringAt(row);
086                if ((text != null) && (text.length() > 0 )) {
087                    Matcher matcher = pattern.matcher(text);
088                    if (matcher.find()) {
089                        return createSearchResult(matcher, row, 0);
090                    }
091                }
092                return null;
093            }
094    
095            @Override
096            protected int getSize() {
097                return tree.getRowCount();
098            }
099    
100            /**
101             * {@inheritDoc}
102             */
103            @Override
104            public JXTree getTarget() {
105                return tree;
106            }
107    
108    
109            /**
110             * {@inheritDoc}
111             */
112            @Override
113            protected void moveMatchMarker() {
114                if (markByHighlighter()) {
115                    moveMatchByHighlighter();
116                } else { // use selection
117                    moveMatchBySelection();
118                }
119            }
120            
121            protected void moveMatchBySelection() {
122    //          // the common behaviour (JXList, JXTable) is to not
123    //          // move the selection if not found
124                if (!hasMatch()) {
125                    return;
126                }
127              tree.setSelectionRow(lastSearchResult.foundRow);
128              tree.scrollRowToVisible(lastSearchResult.foundRow);
129            }
130            
131    
132            /**
133             * use and move the match highlighter.
134             * PRE: markByHighlighter
135             *
136             */
137            protected void moveMatchByHighlighter() {
138                AbstractHighlighter searchHL = getConfiguredMatchHighlighter();
139                // no match
140                if (!hasMatch()) {
141                    return;
142                } else {
143                    ensureInsertedSearchHighlighters(searchHL);
144                    tree.scrollRowToVisible(lastSearchResult.foundRow);
145                }
146            }
147    
148    
149    
150            /**
151             * @param searchHighlighter
152             */
153            @Override
154            protected void removeHighlighter(Highlighter searchHighlighter) {
155                tree.removeHighlighter(searchHighlighter);
156            }
157    
158            /**
159             * @return all registered highlighters
160             */
161            @Override
162            protected Highlighter[] getHighlighters() {
163                return tree.getHighlighters();
164            }
165    
166            /**
167             * @param highlighter
168             */
169            @Override
170            protected void addHighlighter(Highlighter highlighter) {
171                tree.addHighlighter(highlighter);
172            }
173    
174        }