From ac13005c095f15cd044b74cc69a86a0b11b54014 Mon Sep 17 00:00:00 2001 From: Alexey Pegov Date: Thu, 9 Sep 2010 16:05:41 +0400 Subject: [PATCH] SpeedSearch support for sortable tables + different model to view conversion fixes --- .../options/ProcessedModulesTable.java | 8 +- .../ui/configuration/ClasspathPanel.java | 12 ++- .../find/actions/ShowUsagesAction.java | 8 +- .../src/com/intellij/ui/table/TableView.java | 25 ++---- .../ide/plugins/PluginManagerMain.java | 5 ++ .../intellij/ide/util/ElementsChooser.java | 10 ++- .../src/com/intellij/ui/SpeedSearchBase.java | 85 ++++++++++++++++++- .../src/com/intellij/ui/TableSpeedSearch.java | 1 + .../com/intellij/ui/TableViewSpeedSearch.java | 8 +- .../com/intellij/ui/TreeTableSpeedSearch.java | 2 +- .../util/src/com/intellij/ui/TableUtil.java | 4 +- .../CompareWithSelectedRevisionAction.java | 7 +- .../execution/junit2/ui/StatisticsPanel.java | 2 +- .../editors/string/KeyChooserDialog.java | 7 +- 14 files changed, 151 insertions(+), 33 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/options/ProcessedModulesTable.java b/java/compiler/impl/src/com/intellij/compiler/options/ProcessedModulesTable.java index 7a7c97e71e48..227aa6108697 100644 --- a/java/compiler/impl/src/com/intellij/compiler/options/ProcessedModulesTable.java +++ b/java/compiler/impl/src/com/intellij/compiler/options/ProcessedModulesTable.java @@ -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; } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ClasspathPanel.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ClasspathPanel.java index 41efe1c29773..fdff67f4c065 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ClasspathPanel.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ClasspathPanel.java @@ -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); diff --git a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java index 1bfc71009002..12698445dbf4 100644 --- a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java +++ b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java @@ -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)); diff --git a/platform/platform-api/src/com/intellij/ui/table/TableView.java b/platform/platform-api/src/com/intellij/ui/table/TableView.java index ee2c307dd0f8..a98f3b48d471 100644 --- a/platform/platform-api/src/com/intellij/ui/table/TableView.java +++ b/platform/platform-api/src/com/intellij/ui/table/TableView.java @@ -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 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 model) { @@ -66,7 +57,7 @@ public class TableView extends BaseTableView implements ItemsProvider, Sel public TableCellRenderer getCellRenderer(int row, int column) { final ColumnInfo 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 extends BaseTableView implements ItemsProvider, Sel final List 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 extends BaseTableView implements ItemsProvider, Sel public Item getSelectedObject() { final int row = getSelectedRow(); final List 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 extends BaseTableView implements ItemsProvider, Sel final List items = getItems(); final List result = new ArrayList(); for (int selectedRow : selectedRows) { - result.add(items.get(selectedRow)); + result.add(items.get(convertRowIndexToModel(selectedRow))); } return result; } @@ -160,14 +151,14 @@ public class TableView 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 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; } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java index 03c1c6707502..cd7ee71a4e35 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java @@ -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(); } diff --git a/platform/platform-impl/src/com/intellij/ide/util/ElementsChooser.java b/platform/platform-impl/src/com/intellij/ide/util/ElementsChooser.java index d505e1c0a5bd..0a3566bd76a6 100644 --- a/platform/platform-impl/src/com/intellij/ide/util/ElementsChooser.java +++ b/platform/platform-impl/src/com/intellij/ide/util/ElementsChooser.java @@ -100,6 +100,11 @@ public class ElementsChooser 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 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 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; } diff --git a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java index 95c1b02494e0..592c146ca1e4 100644 --- a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java +++ b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java @@ -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 { 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 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 { 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()); + } + } } diff --git a/platform/platform-impl/src/com/intellij/ui/TableSpeedSearch.java b/platform/platform-impl/src/com/intellij/ui/TableSpeedSearch.java index dae9ddfe2a4f..e1061e5c1214 100644 --- a/platform/platform-impl/src/com/intellij/ui/TableSpeedSearch.java +++ b/platform/platform-impl/src/com/intellij/ui/TableSpeedSearch.java @@ -62,6 +62,7 @@ public class TableSpeedSearch extends SpeedSearchBase { 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; } diff --git a/platform/platform-impl/src/com/intellij/ui/TableViewSpeedSearch.java b/platform/platform-impl/src/com/intellij/ui/TableViewSpeedSearch.java index 95088583daff..49089f6e9354 100644 --- a/platform/platform-impl/src/com/intellij/ui/TableViewSpeedSearch.java +++ b/platform/platform-impl/src/com/intellij/ui/TableViewSpeedSearch.java @@ -33,6 +33,11 @@ public abstract class TableViewSpeedSearch extends SpeedSearchBase { 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 { 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; } diff --git a/platform/platform-impl/src/com/intellij/ui/TreeTableSpeedSearch.java b/platform/platform-impl/src/com/intellij/ui/TreeTableSpeedSearch.java index 9e15f4fe5b3d..fe8f529e92d1 100644 --- a/platform/platform-impl/src/com/intellij/ui/TreeTableSpeedSearch.java +++ b/platform/platform-impl/src/com/intellij/ui/TreeTableSpeedSearch.java @@ -47,7 +47,7 @@ public class TreeTableSpeedSearch extends SpeedSearchBase { 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); } diff --git a/platform/util/src/com/intellij/ui/TableUtil.java b/platform/util/src/com/intellij/ui/TableUtil.java index 2c8edb837188..f90d09ac34b2 100644 --- a/platform/util/src/com/intellij/ui/TableUtil.java +++ b/platform/util/src/com/intellij/ui/TableUtil.java @@ -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); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/CompareWithSelectedRevisionAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/CompareWithSelectedRevisionAction.java index 015b7d73dd27..c960bcde89ce 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/CompareWithSelectedRevisionAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/CompareWithSelectedRevisionAction.java @@ -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); } }; diff --git a/plugins/junit/src/com/intellij/execution/junit2/ui/StatisticsPanel.java b/plugins/junit/src/com/intellij/execution/junit2/ui/StatisticsPanel.java index 580d65514b6c..7e79886a764f 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/ui/StatisticsPanel.java +++ b/plugins/junit/src/com/intellij/execution/junit2/ui/StatisticsPanel.java @@ -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); } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/string/KeyChooserDialog.java b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/string/KeyChooserDialog.java index cf68d6c69b91..439a3e83d691 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/string/KeyChooserDialog.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/string/KeyChooserDialog.java @@ -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)); } }