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

com.jidesoft.swing.TableSearchable Maven / Gradle / Ivy

There is a newer version: 3.6.18
Show newest version
/*
 * @(#)TableSearchable.java
 *
 * Copyright 2002 - 2004 JIDE Software Inc. All rights reserved.
 */
package com.jidesoft.swing;

import com.jidesoft.swing.event.SearchableEvent;

import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

/**
 * TableSearchable is an concrete implementation of {@link Searchable} that enables the search function in
 * JTable. 

It's very simple to use it. Assuming you have a JTable, all you need to do is to call *

 * JTable table = ....;
 * TableSearchable searchable = new TableSearchable(table);
 * 
* Now the JTable will have the search function. *

* As JTable is a two dimension data, the search is a little different from JList and JTree which both have one * dimension data. So there is a little work you need to do in order to convert from two dimension data to one dimension * data. We use the selection mode to determine how to convert. There is a special property called mainIndex. You can * set it using setMainIndex(). If the JTable is in row selection mode, mainIndex will be the column that you want * search at. Please note you can change mainIndex at any time. *

* On the other hand, if the JTable is in column selection mode, mainIndex will be the row that you want search at. * There is one more case when cell selection is enabled. In this case, mainIndex will be ignore; all cells will be * searched. *

* In three cases above, the keys for find next and find previous are different too. In row selection mode, up/down * arrow are the keys. In column selection mode, left/right arrow are keys. In cell selection mode, both up and left * arrow are keys to find previous occurrence, both down and right arrow are keys to find next occurrence. *

* In addition, you might need to override convertElementToString() to provide you own algorithm to do the conversion. *

 * JTable table = ....;
 * TableSearchable searchable = new TableSearchable(table) {
 *      protected String convertElementToString(Object object) {
 *          ...
 *      }
 * };
 * 
*

* Additional customization can be done on the base Searchable class such as background and foreground color, * keystrokes, case sensitivity, */ public class TableSearchable extends Searchable implements TableModelListener, PropertyChangeListener { private int[] _searchColumnIndices = {0}; public TableSearchable(JTable table) { super(table); } @Override public void installListeners() { super.installListeners(); if (_component instanceof JTable) { ((JTable) _component).getModel().addTableModelListener(this); _component.addPropertyChangeListener("model", this); } } @Override public void uninstallListeners() { super.uninstallListeners(); if (_component instanceof JTable) { ((JTable) _component).getModel().removeTableModelListener(this); _component.removePropertyChangeListener("model", this); } } @Override protected void setSelectedIndex(int index, boolean incremental) { int majorIndex, minorIndex; JTable table = ((JTable) _component); if (isColumnSelectionAllowed(table)) { minorIndex = index; majorIndex = getMainIndex(); addTableSelection(table, majorIndex, minorIndex, incremental); } else if (isRowSelectionAllowed(table)) { majorIndex = index; minorIndex = table.convertColumnIndexToView(getMainIndex()); addTableSelection(table, majorIndex, minorIndex, incremental); } else { // cell selection allowed int columnCount = table.getColumnCount(); if (columnCount == 0) { return; } majorIndex = index / columnCount; minorIndex = index % columnCount; addTableSelection(table, majorIndex, minorIndex, incremental); } } /** * Selects the cell at the specified row and column index. If incremental is true, the previous selection will not * be cleared. This method will use {@link JTable#changeSelection(int,int,boolean,boolean)} method to select the * cell if the row and column index is in the range and the cell was not selected. The last two parameters of * changeSelection is true and false respectively. * * @param table the table * @param rowIndex the row index of the cell. * @param columnIndex the column index of the cell * @param incremental false to clear all previous selection. True to keep the previous selection. */ protected void addTableSelection(JTable table, int rowIndex, int columnIndex, boolean incremental) { if (!incremental) table.clearSelection(); if (rowIndex >= 0 && columnIndex >= 0 && rowIndex < table.getRowCount() && columnIndex < table.getColumnCount() && !table.isCellSelected(rowIndex, columnIndex)) { table.changeSelection(rowIndex, columnIndex, true, false); } } /** * Is the column selection allowed? * * @param table the table. * @return true if the table is the column selection. */ protected boolean isColumnSelectionAllowed(JTable table) { // NOTES: must sync with TableShrinkSearchableSupport#isColumnSelectionAllowed. return getSearchColumnIndices().length == 1 && (table.getColumnSelectionAllowed() && !table.getRowSelectionAllowed()); } /** * Is the row selection allowed? * * @param table the table. * @return true if the table is the row selection. */ protected boolean isRowSelectionAllowed(JTable table) { // NOTES: must sync with TableShrinkSearchableSupport#isRowSelectionAllowed. return getSearchColumnIndices().length == 1 && (!table.getColumnSelectionAllowed() && table.getRowSelectionAllowed()); } /** * Are we trying to search on multi-columns (but NOT all columns)? * * @return true if the search is set to look at multi-columns (but NOT all columns). */ protected boolean isSearchSelectedRows() { return getSearchColumnIndices().length > 1; } /** * Gets the selected index. * * @return the selected index. */ @Override protected int getSelectedIndex() { JTable table = (JTable) _component; if (isColumnSelectionAllowed(table)) { return table.getColumnModel().getSelectionModel().getAnchorSelectionIndex(); } else if (isRowSelectionAllowed(table)) { return table.getSelectionModel().getAnchorSelectionIndex(); } else { // cell selection allowed return table.getSelectionModel().getAnchorSelectionIndex() * table.getColumnCount() + table.getColumnModel().getSelectionModel().getAnchorSelectionIndex(); } } @Override protected Object getElementAt(int index) { JTable table = (JTable) _component; if (isColumnSelectionAllowed(table)) { // column selection mode return getValueAt(table, getMainIndex(), index); } else if (isRowSelectionAllowed(table)) { // row selection mode return getValueAt(table, index, table.convertColumnIndexToView(getMainIndex())); } else if (isSearchSelectedRows()) { // search on multi columns int columnIndex = index % table.getColumnCount(); int modelIndex = table.convertColumnIndexToModel(columnIndex); boolean doNotSearch = true; for (int i : getSearchColumnIndices()) { if (i == modelIndex) { doNotSearch = false; } } if (doNotSearch) { return null; } int rowIndex = index / table.getColumnCount(); return getValueAt(table, rowIndex, columnIndex); } else { // cell selection allowed int columnIndex = index % table.getColumnCount(); int rowIndex = index / table.getColumnCount(); return getValueAt(table, rowIndex, columnIndex); } } /** * Get string value of the table. * * @param table the JTable * @param rowIndex the row index * @param columnIndex the column index * @return the string value of the cell in the table. */ protected Object getValueAt(JTable table, int rowIndex, int columnIndex) { if (rowIndex >= 0 && rowIndex < table.getRowCount() && columnIndex >= 0 && columnIndex < table.getColumnCount()) { return table.getValueAt(rowIndex, columnIndex); } else { return null; } } @Override protected int getElementCount() { JTable table = ((JTable) _component); if (isColumnSelectionAllowed(table)) { return table.getColumnCount(); } else if (isRowSelectionAllowed(table)) { return table.getRowCount(); } else { // cell selection allowed return table.getColumnCount() * table.getRowCount(); } } @Override protected String convertElementToString(Object item) { if (item != null) { return item.toString(); } else { return ""; } } /** * Gets the indexes of the column to be searched. * * @return the indexes of the column to be searched. */ public int[] getSearchColumnIndices() { return _searchColumnIndices; } /** * Gets the index of the column to be searched. * * @return the index of the column to be searched. */ public int getMainIndex() { if (_searchColumnIndices.length == 0) { return -1; } return _searchColumnIndices[0]; } /** * Sets the main indexes. Main indexes are the columns index which you want to be searched. * * @param columnIndices the index of the columns to be searched. If empty, all columns will be searched. */ public void setSearchColumnIndices(int[] columnIndices) { if (columnIndices == null) { columnIndices = new int[0]; } int[] old = _searchColumnIndices; if (!JideSwingUtilities.equals(old, columnIndices, true)) { _searchColumnIndices = columnIndices; hidePopup(); } } /** * Sets the main index. Main index is the column index which you want to be searched. * * @param mainIndex the index of the column to be searched. If -1, all columns will be searched. */ public void setMainIndex(int mainIndex) { int[] temp = {mainIndex}; if (mainIndex < 0) { temp = new int[0]; } int[] old = _searchColumnIndices; if (old != temp) { _searchColumnIndices = temp; hidePopup(); } } @Override protected boolean isFindNextKey(KeyEvent e) { int keyCode = e.getKeyCode(); JTable table = ((JTable) _component); if (isColumnSelectionAllowed(table)) { return keyCode == KeyEvent.VK_RIGHT; } else if (isRowSelectionAllowed(table)) { return keyCode == KeyEvent.VK_DOWN; } else { // cell selection allowed return keyCode == KeyEvent.VK_DOWN || keyCode == KeyEvent.VK_RIGHT; } } @Override protected boolean isFindPreviousKey(KeyEvent e) { int keyCode = e.getKeyCode(); JTable table = ((JTable) _component); if (isColumnSelectionAllowed(table)) { return keyCode == KeyEvent.VK_LEFT; } else if (isRowSelectionAllowed(table)) { return keyCode == KeyEvent.VK_UP; } else { // cell selection allowed return keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_LEFT; } } public void tableChanged(TableModelEvent e) { if (isProcessModelChangeEvent()) { hidePopup(); fireSearchableEvent(new SearchableEvent(this, SearchableEvent.SEARCHABLE_MODEL_CHANGE)); } } public void propertyChange(PropertyChangeEvent evt) { if ("model".equals(evt.getPropertyName())) { hidePopup(); if (evt.getOldValue() instanceof TableModel) { ((TableModel) evt.getOldValue()).removeTableModelListener(this); } if (evt.getNewValue() instanceof TableModel) { ((TableModel) evt.getNewValue()).addTableModelListener(this); } fireSearchableEvent(new SearchableEvent(this, SearchableEvent.SEARCHABLE_MODEL_CHANGE)); } } @Override protected boolean isActivateKey(KeyEvent e) { boolean editable = isSelectedCellEditable(); return !editable && super.isActivateKey(e); } /** * Checks if the selected cell is editable. If yes, we will not activate Searchable when key is typed. * * @return true if the selected cell is editable. */ protected boolean isSelectedCellEditable() { int selectedRow = ((JTable) _component).getSelectedRow(); int selectedColumn = ((JTable) _component).getSelectedColumn(); return selectedRow != -1 && selectedColumn != -1 && ((JTable) _component).isCellEditable(selectedRow, selectedColumn); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy