SpeedSearch support for sortable tables + different model to view conversion fixes

This commit is contained in:
Alexey Pegov
2010-09-09 16:05:41 +04:00
parent 46cfb16552
commit ac13005c09
14 changed files with 151 additions and 33 deletions
@@ -111,6 +111,11 @@ public class ProcessedModulesTable extends JPanel {
return myTable.getSelectedRow();
}
@Override
protected int convertIndexToModel(int viewIndex) {
return myTable.convertRowIndexToModel(viewIndex);
}
public Object[] getAllElements() {
final int count = myTableModel.getRowCount();
Object[] elements = new Object[count];
@@ -128,7 +133,8 @@ public class ProcessedModulesTable extends JPanel {
final int count = myTableModel.getRowCount();
for (int row = 0; row < count; row++) {
if (element.equals(myTableModel.getModuleAt(row))) {
myTable.getSelectionModel().setSelectionInterval(row, row);
final int viewRow = myTable.convertRowIndexToView(row);
myTable.getSelectionModel().setSelectionInterval(viewRow, viewRow);
TableUtil.scrollSelectionToVisible(myTable);
break;
}
@@ -111,6 +111,11 @@ public class ClasspathPanel extends JPanel {
return myEntryTable.getSelectedRow();
}
@Override
protected int convertIndexToModel(int viewIndex) {
return myEntryTable.convertRowIndexToModel(viewIndex);
}
public Object[] getAllElements() {
final int count = myModel.getRowCount();
Object[] elements = new Object[count];
@@ -128,7 +133,8 @@ public class ClasspathPanel extends JPanel {
final int count = myModel.getRowCount();
for (int row = 0; row < count; row++) {
if (element.equals(myModel.getItemAt(row))) {
myEntryTable.getSelectionModel().setSelectionInterval(row, row);
final int viewRow = myEntryTable.convertRowIndexToView(row);
myEntryTable.getSelectionModel().setSelectionInterval(viewRow, viewRow);
TableUtil.scrollSelectionToVisible(myEntryTable);
break;
}
@@ -146,14 +152,14 @@ public class ClasspathPanel extends JPanel {
final int[] selectedRows = myEntryTable.getSelectedRows();
boolean currentlyMarked = true;
for (final int selectedRow : selectedRows) {
final TableItem item = myModel.getItemAt(selectedRow);
final TableItem item = myModel.getItemAt(myEntryTable.convertRowIndexToModel(selectedRow));
if (selectedRow < 0 || !item.isExportable()) {
return;
}
currentlyMarked &= item.isExported();
}
for (final int selectedRow : selectedRows) {
myModel.getItemAt(selectedRow).setExported(!currentlyMarked);
myModel.getItemAt(myEntryTable.convertRowIndexToModel(selectedRow)).setExported(!currentlyMarked);
}
myModel.fireTableDataChanged();
TableUtil.selectRows(myEntryTable, selectedRows);
@@ -377,6 +377,11 @@ public class ShowUsagesAction extends AnAction {
return table.getSelectedRow();
}
@Override
protected int convertIndexToModel(int viewIndex) {
return table.convertRowIndexToModel(viewIndex);
}
protected Object[] getAllElements() {
return ArrayUtil.toObjectArray(data);
}
@@ -393,7 +398,8 @@ public class ShowUsagesAction extends AnAction {
protected void selectElement(Object element, String selectedText) {
int i = data.indexOf(element);
if (i == -1) return;
table.getSelectionModel().setSelectionInterval(i, i);
final int viewRow = table.convertRowIndexToView(i);
table.getSelectionModel().setSelectionInterval(viewRow, viewRow);
}
};
speedSearch.setComparator(new SpeedSearchBase.SpeedSearchComparator(false));
@@ -24,7 +24,6 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.*;
import java.awt.*;
import java.util.ArrayList;
@@ -45,14 +44,6 @@ public class TableView<Item> extends BaseTableView implements ItemsProvider, Sel
public void setModel(final TableModel dataModel) {
assert dataModel instanceof SortableColumnModel : "SortableColumnModel required";
super.setModel(dataModel);
dataModel.addTableModelListener(new TableModelListener() {
public void tableChanged(final TableModelEvent e) {
JTableHeader header = getTableHeader();
if (header != null) {
header.repaint();
}
}
});
}
public void setModel(final ListTableModel<Item> model) {
@@ -66,7 +57,7 @@ public class TableView<Item> extends BaseTableView implements ItemsProvider, Sel
public TableCellRenderer getCellRenderer(int row, int column) {
final ColumnInfo<Item, ?> columnInfo = getListTableModel().getColumnInfos()[convertColumnIndexToModel(column)];
TableCellRenderer renderer = columnInfo.getRenderer(getListTableModel().getItems().get(row));
TableCellRenderer renderer = columnInfo.getRenderer(getListTableModel().getItems().get(convertRowIndexToModel(row)));
if (renderer == null) {
return super.getCellRenderer(row, column);
}
@@ -128,9 +119,9 @@ public class TableView<Item> extends BaseTableView implements ItemsProvider, Sel
final List<Item> items = getItems();
if (! items.isEmpty()) {
for (int selectedRow : selectedRows) {
final int correctedIndex = convertRowIndexToModel(selectedRow);
if (correctedIndex >= 0 && correctedIndex < items.size()) {
result.add(items.get(correctedIndex));
final int modelIndex = convertRowIndexToModel(selectedRow);
if (modelIndex >= 0 && modelIndex < items.size()) {
result.add(items.get(modelIndex));
}
}
}
@@ -141,7 +132,7 @@ public class TableView<Item> extends BaseTableView implements ItemsProvider, Sel
public Item getSelectedObject() {
final int row = getSelectedRow();
final List<Item> list = getItems();
return row >= 0 && row < list.size() ? list.get(row) : null;
return row >= 0 && row < list.size() ? list.get(convertRowIndexToModel(row)) : null;
}
@Nullable
@@ -151,7 +142,7 @@ public class TableView<Item> extends BaseTableView implements ItemsProvider, Sel
final List<Item> items = getItems();
final List<Item> result = new ArrayList<Item>();
for (int selectedRow : selectedRows) {
result.add(items.get(selectedRow));
result.add(items.get(convertRowIndexToModel(selectedRow)));
}
return result;
}
@@ -160,14 +151,14 @@ public class TableView<Item> extends BaseTableView implements ItemsProvider, Sel
List items = getItems();
if (!items.contains(item)) return;
int index = items.indexOf(item);
getSelectionModel().addSelectionInterval(index, index);
getSelectionModel().addSelectionInterval(convertRowIndexToView(index), convertRowIndexToView(index));
// fix cell selection case
getColumnModel().getSelectionModel().addSelectionInterval(0, getColumnCount()-1);
}
public TableCellEditor getCellEditor(int row, int column) {
final ColumnInfo<Item, ?> columnInfo = getListTableModel().getColumnInfos()[convertColumnIndexToModel(column)];
final TableCellEditor editor = columnInfo.getEditor(getListTableModel().getItems().get(row));
final TableCellEditor editor = columnInfo.getEditor(getListTableModel().getItems().get(convertRowIndexToModel(row)));
return editor == null ? super.getCellEditor(row, column) : editor;
}
@@ -557,6 +557,11 @@ public class PluginManagerMain implements Disposable {
super(cmp);
}
@Override
protected int convertIndexToModel(int viewIndex) {
return getComponent().convertRowIndexToModel(viewIndex);
}
public int getSelectedIndex() {
return myComponent.getSelectedRow();
}
@@ -100,6 +100,11 @@ public class ElementsChooser<T> extends JPanel {
return myTable.getSelectedRow();
}
@Override
protected int convertIndexToModel(int viewIndex) {
return myTable.convertRowIndexToModel(viewIndex);
}
public Object[] getAllElements() {
final int count = myTableModel.getRowCount();
Object[] elements = new Object[count];
@@ -117,7 +122,8 @@ public class ElementsChooser<T> extends JPanel {
final int count = myTableModel.getRowCount();
for (int row = 0; row < count; row++) {
if (element.equals(myTableModel.getElementAt(row))) {
myTable.getSelectionModel().setSelectionInterval(row, row);
final int viewRow = myTable.convertRowIndexToView(row);
myTable.getSelectionModel().setSelectionInterval(viewRow, viewRow);
TableUtil.scrollSelectionToVisible(myTable);
break;
}
@@ -302,7 +308,7 @@ public class ElementsChooser<T> extends JPanel {
final int[] rows = new int[elements.size()];
int index = 0;
for (final T element : elements) {
rows[index++] = myTableModel.getElementRow(element);
rows[index++] = myTable.convertRowIndexToView(myTableModel.getElementRow(element));
}
return rows;
}
@@ -29,6 +29,7 @@ import com.intellij.openapi.wm.ex.ToolWindowManagerListener;
import com.intellij.util.StringBuilderSpinAllocator;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -42,8 +43,8 @@ import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Arrays;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
@@ -87,17 +88,31 @@ public abstract class SpeedSearchBase<Comp extends JComponent> {
return speedSearch != null && speedSearch.mySearchPopup != null && speedSearch.mySearchPopup.isVisible();
}
/**
* Returns visual (view) selection index.
*/
protected abstract int getSelectedIndex();
protected abstract Object[] getAllElements();
protected abstract String getElementText(Object element);
/**
* Should convert given view index to model index
*/
protected int convertIndexToModel(final int viewIndex) {
return viewIndex;
}
/**
* @param element Element to select. Don't forget to convert model index to view index if needed (i.e. table.convertRowIndexToView(modelIndex), etc).
* @param selectedText search text
*/
protected abstract void selectElement(Object element, String selectedText);
protected ListIterator<Object> getElementIterator(int startingIndex) {
final Object[] allElements = getAllElements();
return Arrays.asList(allElements).listIterator(startingIndex < 0? allElements.length : startingIndex);
return new ViewIterator(this, startingIndex < 0 ? allElements.length : startingIndex);
}
public void addChangeListener(PropertyChangeListener listener) {
@@ -536,4 +551,70 @@ public abstract class SpeedSearchBase<Comp extends JComponent> {
manageSearchPopup(null);
}
}
protected class ViewIterator implements ListIterator {
private SpeedSearchBase mySpeedSearch;
private int myCurrentIndex;
private Object[] myElements;
public ViewIterator(@NotNull final SpeedSearchBase speedSearch, final int startIndex) {
mySpeedSearch = speedSearch;
myCurrentIndex = startIndex;
myElements = speedSearch.getAllElements();
if (startIndex < 0 || startIndex > myElements.length) {
throw new IndexOutOfBoundsException("Index: " + startIndex);
}
}
@Override
public boolean hasPrevious() {
return myCurrentIndex != 0;
}
@Override
public Object previous() {
final int i = myCurrentIndex - 1;
if (i < 0) throw new NoSuchElementException();
final Object previous = myElements[mySpeedSearch.convertIndexToModel(i)];
myCurrentIndex = i;
return previous;
}
@Override
public int nextIndex() {
return myCurrentIndex;
}
@Override
public int previousIndex() {
return myCurrentIndex - 1;
}
@Override
public boolean hasNext() {
return myCurrentIndex != myElements.length;
}
@Override
public Object next() {
if (myCurrentIndex + 1 > myElements.length) throw new NoSuchElementException();
return myElements[mySpeedSearch.convertIndexToModel(myCurrentIndex++)];
}
@Override
public void remove() {
throw new UnsupportedOperationException("Not implemented in: " + getClass().getCanonicalName());
}
@Override
public void set(Object o) {
throw new UnsupportedOperationException("Not implemented in: " + getClass().getCanonicalName());
}
@Override
public void add(Object o) {
throw new UnsupportedOperationException("Not implemented in: " + getClass().getCanonicalName());
}
}
}
@@ -62,6 +62,7 @@ public class TableSpeedSearch extends SpeedSearchBase<JTable> {
protected int getSelectedIndex() {
final int row = myComponent.getSelectedRow();
final int col = myComponent.getSelectedColumn();
// TODO: WTF?! getComponent().getSelectedRow() should be enough for everyone.
return row > -1 && col > -1? row * myComponent.getModel().getColumnCount() + col : -1;
}
@@ -33,6 +33,11 @@ public abstract class TableViewSpeedSearch extends SpeedSearchBase<TableView> {
return getComponent().getSelectedRow();
}
@Override
protected int convertIndexToModel(int viewIndex) {
return myComponent.convertRowIndexToModel(viewIndex);
}
@Override
protected Object[] getAllElements() {
return getComponent().getItems().toArray();
@@ -47,7 +52,8 @@ public abstract class TableViewSpeedSearch extends SpeedSearchBase<TableView> {
for (int i = 0, itemsSize = items.size(); i < itemsSize; i++) {
final Object o = items.get(i);
if (o == element) {
getComponent().getSelectionModel().setSelectionInterval(i, i);
final int viewIndex = myComponent.convertRowIndexToView(i);
getComponent().getSelectionModel().setSelectionInterval(viewIndex, viewIndex);
TableUtil.scrollSelectionToVisible(getComponent());
break;
}
@@ -47,7 +47,7 @@ public class TreeTableSpeedSearch extends SpeedSearchBase<TreeTable> {
protected void selectElement(Object element, String selectedText) {
final TreePath treePath = (TreePath)element;
TableUtil.selectRows(myComponent, new int[] {myComponent.getTree().getRowForPath(treePath)});
TableUtil.selectRows(myComponent, new int[] {myComponent.convertRowIndexToView(myComponent.getTree().getRowForPath(treePath))});
TableUtil.scrollSelectionToVisible(myComponent);
}
@@ -39,11 +39,11 @@ public class TableUtil {
return removeSelectedItems(table, null);
}
public static void selectRows(JTable table, int[] rows) {
public static void selectRows(final JTable table, final int[] viewRows) {
ListSelectionModel selectionModel = table.getSelectionModel();
selectionModel.clearSelection();
int count = table.getRowCount();
for (int row : rows) {
for (int row : viewRows) {
if (row >= 0 && row < count) {
selectionModel.addSelectionInterval(row, row);
}
@@ -238,6 +238,11 @@ public class CompareWithSelectedRevisionAction extends AbstractVcsAction {
return table.getSelectedRow();
}
@Override
protected int convertIndexToModel(int viewIndex) {
return table.convertRowIndexToModel(viewIndex);
}
protected Object[] getAllElements() {
return revisions.toArray();
}
@@ -249,7 +254,7 @@ public class CompareWithSelectedRevisionAction extends AbstractVcsAction {
protected void selectElement(Object element, String selectedText) {
VcsFileRevision revision = (VcsFileRevision) element;
TableUtil.selectRows(myComponent, new int[] {revisions.indexOf(revision)});
TableUtil.selectRows(myComponent, new int[] {myComponent.convertRowIndexToView(revisions.indexOf(revision))});
TableUtil.scrollSelectionToVisible(myComponent);
}
};
@@ -87,7 +87,7 @@ class StatisticsPanel extends JPanel implements DataProvider{
myTimeLabel.clear();
myTimeLabel.append("Total time: " + Formatters.statisticsFor(proxy).getTime(), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
final int idx = myChildInfo.getIndexOf(myCurrentTest);
TableUtil.selectRows(myTable, new int[]{idx});
TableUtil.selectRows(myTable, new int[]{myTable.convertRowIndexToView(idx)});
TableUtil.scrollSelectionToVisible(myTable);
}
@@ -260,6 +260,11 @@ public final class KeyChooserDialog extends DialogWrapper{
super(component);
}
@Override
protected int convertIndexToModel(int viewIndex) {
return getComponent().convertRowIndexToModel(viewIndex);
}
public int getSelectedIndex() {
return myComponent.getSelectedRow();
}
@@ -283,7 +288,7 @@ public final class KeyChooserDialog extends DialogWrapper{
public void selectElement(final Object element, final String selectedText) {
final int index = myElements.get(element);
selectElementAt(index);
selectElementAt(getComponent().convertRowIndexToView(index));
}
}