All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jdesktop.swingx.search.TableSearchable Maven / Gradle / Ivy

There is a newer version: 1.7.2
Show newest version
/*
 * $Id: TableSearchable.java 3194 2009-01-21 11:39:19Z kleopatra $
 *
 * Copyright 2007 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
package org.jdesktop.swingx.search;

import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.decorator.AbstractHighlighter;
import org.jdesktop.swingx.decorator.Highlighter;

import java.awt.Rectangle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * An Searchable implementation for use in JXTable.
 *
 * @author Jeanette Winzenburg
 */
public class TableSearchable extends AbstractSearchable {

    /**
     * The target JXTable.
     */
    protected JXTable table;

    /**
     * Instantiates a TableSearchable with the given table as target.
     *
     * @param table the JXTable to search.
     */
    public TableSearchable(JXTable table) {
        this.table = table;
    }

    /**
     * {@inheritDoc}
     * 

*

* This implementation loops through the cells in a row to find a match. */ @Override protected void findMatchAndUpdateState(Pattern pattern, int startRow, boolean backwards) { SearchResult matchRow = null; if (backwards) { // CHECK: off-one end still needed? // Probably not - the findXX don't have side-effects any longer // hmmm... still needed: even without side-effects we need to // guarantee calling the notfound update at the very end of the // loop. for (int r = startRow; r >= -1 && matchRow == null; r--) { matchRow = findMatchBackwardsInRow(pattern, r); updateState(matchRow); } } else { for (int r = startRow; r <= getSize() && matchRow == null; r++) { matchRow = findMatchForwardInRow(pattern, r); updateState(matchRow); } } // KEEP - JW: Needed to update if loop wasn't entered! // the alternative is to go one off in the loop. Hmm - which is // preferable? // updateState(matchRow); } /** * {@inheritDoc} *

*

* Implemented to search for an extension in the cell given by row and * foundColumn. */ @Override protected SearchResult findExtendedMatch(Pattern pattern, int row) { return findMatchAt(pattern, row, lastSearchResult.foundColumn); } /** * Searches forward through columns of the given row. Starts at * lastFoundColumn or first column if lastFoundColumn < 0. returns an * appropriate SearchResult if a matching cell is found in this row or null * if no match is found. A row index out off range results in a no-match. * * @param pattern Pattern that we will try to locate * @param row the row to search * @return an appropriate SearchResult if a matching cell is * found in this row or null if no match is found */ private SearchResult findMatchForwardInRow(Pattern pattern, int row) { int startColumn = Math.max(lastSearchResult.foundColumn, 0); if (isValidIndex(row)) { for (int column = startColumn; column < table.getColumnCount(); column++) { SearchResult result = findMatchAt(pattern, row, column); if (result != null) return result; } } return null; } /** * Searches forward through columns of the given row. Starts at * lastFoundColumn or first column if lastFoundColumn < 0. returns an * appropriate SearchResult if a matching cell is found in this row or null * if no match is found. A row index out off range results in a no-match. * * @param pattern Pattern that we will try to locate * @param row the row to search * @return an appropriate SearchResult if a matching cell is * found in this row or null if no match is found */ private SearchResult findMatchBackwardsInRow(Pattern pattern, int row) { int startColumn = lastSearchResult.foundColumn < 0 ? table.getColumnCount() - 1 : lastSearchResult.foundColumn; if (isValidIndex(row)) { for (int column = startColumn; column >= 0; column--) { SearchResult result = findMatchAt(pattern, row, column); if (result != null) return result; } } return null; } /** * Matches the cell content at row/col against the given Pattern. Returns an * appropriate SearchResult if matching or null if no matching * * @param pattern Pattern that we will try to locate * @param row a valid row index in view coordinates * @param column a valid column index in view coordinates * @return an appropriate SearchResult if matching or null */ protected SearchResult findMatchAt(Pattern pattern, int row, int column) { String text = table.getStringAt(row, column); if (text != null && text.length() > 0) { Matcher matcher = pattern.matcher(text); if (matcher.find()) { return createSearchResult(matcher, row, column); } } return null; } /** * {@inheritDoc} *

*

* Overridden to adjust the column index to -1. */ @Override protected int adjustStartPosition(int startIndex, boolean backwards) { lastSearchResult.foundColumn = -1; return super.adjustStartPosition(startIndex, backwards); } /** * {@inheritDoc} *

*

* Overridden to loop through all columns in a row. */ @Override protected int moveStartPosition(int startRow, boolean backwards) { if (backwards) { lastSearchResult.foundColumn--; if (lastSearchResult.foundColumn < 0) { startRow--; } } else { lastSearchResult.foundColumn++; if (lastSearchResult.foundColumn >= table.getColumnCount()) { lastSearchResult.foundColumn = -1; startRow++; } } return startRow; } /** * {@inheritDoc} *

*

* Overridden to check the column index of last find. */ @Override protected boolean isEqualStartIndex(int startIndex) { return super.isEqualStartIndex(startIndex) && isValidColumn(lastSearchResult.foundColumn); } /** * Checks if row is in range: 0 <= row < getRowCount(). * * @param column the column index to check in view coordinates. * @return true if the column is in range, false otherwise */ private boolean isValidColumn(int column) { return column >= 0 && column < table.getColumnCount(); } /** * {@inheritDoc} */ @Override protected int getSize() { return table.getRowCount(); } /** * {@inheritDoc} */ @Override public JXTable getTarget() { return table; } /** * Configures the match highlighter to the current match. Ensures that the * matched cell is visible, if there is a match. *

* PRE: markByHighlighter */ protected void moveMatchByHighlighter() { AbstractHighlighter searchHL = getConfiguredMatchHighlighter(); // no match if (!hasMatch()) return; ensureInsertedSearchHighlighters(searchHL); table.scrollCellToVisible(lastSearchResult.foundRow, lastSearchResult.foundColumn); } /** * {@inheritDoc} *

*

* Overridden to convert the column index in the table's view coordinate * system to model coordinate. *

*

* PENDING JW: this is only necessary because the SearchPredicate wants its * highlight column in model coordinates. But code comments in the * SearchPredicate seem to indicate that we probably want to revise that * (legacy?). */ @Override protected int convertColumnIndexToModel(int viewColumn) { return getTarget().convertColumnIndexToModel(viewColumn); } /** * Moves the row selection to the matching cell and ensures its visibility, * if any. Does nothing if there is no match. */ protected void moveMatchBySelection() { if (!hasMatch()) { return; } int row = lastSearchResult.foundRow; int column = lastSearchResult.foundColumn; table.changeSelection(row, column, false, false); if (!table.getAutoscrolls()) { // scrolling not handled by moving selection Rectangle cellRect = table.getCellRect(row, column, true); if (cellRect != null) { table.scrollRectToVisible(cellRect); } } } /** * {@inheritDoc} *

*/ @Override protected void moveMatchMarker() { if (markByHighlighter()) { moveMatchByHighlighter(); } else { // use selection moveMatchBySelection(); } } /** * {@inheritDoc} *

*/ @Override protected void removeHighlighter(Highlighter searchHighlighter) { table.removeHighlighter(searchHighlighter); } /** * {@inheritDoc} *

*/ @Override protected Highlighter[] getHighlighters() { return table.getHighlighters(); } /** * {@inheritDoc} *

*/ @Override protected void addHighlighter(Highlighter highlighter) { table.addHighlighter(highlighter); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy