EA-138425 - CCE: FilteringListModel.remove

Also ListUtil cleanup, generics and more extension methods
This commit is contained in:
Gregory.Shrago
2019-03-01 20:45:28 +03:00
parent bde2804fbe
commit 85ff3d541f
4 changed files with 118 additions and 142 deletions
@@ -15,7 +15,6 @@
*/
package com.intellij.ui;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Condition;
import com.intellij.ui.speedSearch.FilteringListModel;
import com.intellij.util.ui.UIUtil;
@@ -28,13 +27,13 @@ import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ListUtil {
public static final String SELECTED_BY_MOUSE_EVENT = "byMouseEvent";
private static final Logger LOG = Logger.getInstance("#com.intellij.ui.ListUtil");
public static MouseMotionListener installAutoSelectOnMouseMove(final JList list) {
public static <T> MouseMotionListener installAutoSelectOnMouseMove(@NotNull JList<T> list) {
final MouseMotionAdapter listener = new MouseMotionAdapter() {
boolean myIsEngaged = false;
@@ -77,34 +76,50 @@ public class ListUtil {
protected abstract void update();
}
public static List removeSelectedItems(JList list) {
@NotNull
public static <T> List<T> removeSelectedItems(@NotNull JList<T> list) {
return removeSelectedItems(list, null);
}
public static <T> List<T> removeIndices(JList<T> list, int[] indices) {
@NotNull
public static <T> List<T> removeIndices(@NotNull JList<T> list, int[] indices) {
return removeIndices(list, indices, null);
}
public static <T> List<T> removeSelectedItems(JList list, Condition<? super T> condition) {
int[] idxs = list.getSelectedIndices();
return removeIndices(list, idxs, condition);
@NotNull
public static <T> List<T> removeSelectedItems(@NotNull JList<T> list, @Nullable Condition<? super T> condition) {
int[] indices = list.getSelectedIndices();
return removeIndices(list, indices, condition);
}
private static <T> List<T> removeIndices(JList list, int[] idxs, Condition<? super T> condition) {
if (idxs.length == 0) {
public static <T> void removeItem(@NotNull ListModel<T> model, int index) {
getExtension(model).remove(model, index);
}
public static <T> void removeAllItems(@NotNull ListModel<T> model) {
getExtension(model).removeAll(model);
}
public static <T> void addAllItems(@NotNull ListModel<T> model, @NotNull List<T> items) {
getExtension(model).addAll(model, items);
}
private static <T> List<T> removeIndices(@NotNull JList<T> list, @NotNull int[] indices, @Nullable Condition<? super T> condition) {
if (indices.length == 0) {
return new ArrayList<>(0);
}
ListModel model = list.getModel();
int firstSelectedIndex = idxs[0];
ListModel<T> model = list.getModel();
ListModelExtension<T, ListModel<T>> extension = getExtension(model);
int firstSelectedIndex = indices[0];
ArrayList<T> removedItems = new ArrayList<>();
int deletedCount = 0;
for (int idx1 : idxs) {
for (int idx1 : indices) {
int index = idx1 - deletedCount;
if (index < 0 || index >= model.getSize()) continue;
T obj = (T)get(model, index);
T obj = extension.get(model, index);
if (condition == null || condition.value(obj)) {
removedItems.add(obj);
remove(model, index);
extension.remove(model, index);
deletedCount++;
}
}
@@ -113,31 +128,31 @@ public class ListUtil {
}
else if (list.getSelectedValue() == null) {
// if nothing remains selected, set selected row
if (firstSelectedIndex >= model.getSize()){
if (firstSelectedIndex >= model.getSize()) {
list.setSelectedIndex(model.getSize() - 1);
}
else{
else {
list.setSelectedIndex(firstSelectedIndex);
}
}
return removedItems;
}
public static boolean canRemoveSelectedItems(JList list){
public static <T> boolean canRemoveSelectedItems(@NotNull JList<T> list) {
return canRemoveSelectedItems(list, null);
}
public static boolean canRemoveSelectedItems(JList list, Condition applyable){
ListModel model = list.getModel();
int[] idxs = list.getSelectedIndices();
if (idxs.length == 0) {
public static <T> boolean canRemoveSelectedItems(@NotNull JList<T> list, @Nullable Condition<? super T> condition) {
int[] indices = list.getSelectedIndices();
if (indices.length == 0) {
return false;
}
for (int index : idxs) {
ListModel<T> model = list.getModel();
ListModelExtension<T, ListModel<T>> extension = getExtension(model);
for (int index : indices) {
if (index < 0 || index >= model.getSize()) continue;
Object obj = getExtensions(model).get(model, index);
if (applyable == null || applyable.value(obj)) {
T obj = extension.get(model, index);
if (condition == null || condition.value(obj)) {
return true;
}
}
@@ -145,77 +160,51 @@ public class ListUtil {
return false;
}
public static int moveSelectedItemsUp(JList list) {
DefaultListModel model = getModel(list);
public static <T> int moveSelectedItemsUp(@NotNull JList<T> list) {
ListModel<T> model = list.getModel();
ListModelExtension<T, ListModel<T>> extension = getExtension(model);
int[] indices = list.getSelectedIndices();
if (!canMoveSelectedItemsUp(list)) return 0;
for (int index : indices) {
Object temp = model.get(index);
model.set(index, model.get(index - 1));
model.set(index - 1, temp);
T temp = extension.get(model, index);
extension.set(model, index, extension.get(model, index - 1));
extension.set(model, index - 1, temp);
list.removeSelectionInterval(index, index);
list.addSelectionInterval(index - 1, index - 1);
}
Rectangle cellBounds = list.getCellBounds(indices[0] - 1, indices[indices.length - 1] - 1);
if (cellBounds != null){
if (cellBounds != null) {
list.scrollRectToVisible(cellBounds);
}
return indices.length;
}
public static boolean canMoveSelectedItemsUp(JList list) {
public static <T> boolean canMoveSelectedItemsUp(@NotNull JList<T> list) {
int[] indices = list.getSelectedIndices();
return indices.length > 0 && indices[0] > 0;
}
public static int moveSelectedItemsDown(JList list) {
DefaultListModel model = getModel(list);
public static <T> int moveSelectedItemsDown(@NotNull JList<T> list) {
ListModel<T> model = list.getModel();
ListModelExtension<T, ListModel<T>> extension = getExtension(model);
int[] indices = list.getSelectedIndices();
if (!canMoveSelectedItemsDown(list)) return 0;
for(int i = indices.length - 1; i >= 0 ; i--){
for (int i = indices.length - 1; i >= 0; i--) {
int index = indices[i];
Object temp = model.get(index);
model.set(index, model.get(index + 1));
model.set(index + 1, temp);
T temp = extension.get(model, index);
extension.set(model, index, extension.get(model, index + 1));
extension.set(model, index + 1, temp);
list.removeSelectionInterval(index, index);
list.addSelectionInterval(index + 1, index + 1);
}
Rectangle cellBounds = list.getCellBounds(indices[0] + 1, indices[indices.length - 1] + 1);
if (cellBounds != null){
if (cellBounds != null) {
list.scrollRectToVisible(cellBounds);
}
return indices.length;
}
private static DefaultListModel getModel(JList list) {
final ListModel model = list.getModel();
if (model instanceof FilteringListModel) {
return (DefaultListModel)((FilteringListModel)model).getOriginalModel();
}
if (model instanceof CollectionListModel) {
return getWrapperModel(((CollectionListModel)model));
}
return (DefaultListModel)model;
}
private static DefaultListModel getWrapperModel(final CollectionListModel source) {
DefaultListModel model = new DefaultListModel() {
@Override
public Object set(int index, Object element) {
Object o = source.getElementAt(index);
source.setElementAt(element, index);
return o;
}
@Override
public Object get(int index) {
return source.getElementAt(index);
}
};
return model;
}
public static boolean isPointOnSelection(@NotNull JList list, int x, int y) {
public static <T> boolean isPointOnSelection(@NotNull JList<T> list, int x, int y) {
int row = list.locationToIndex(new Point(x, y));
if (row < 0) return false;
return list.isSelectedIndex(row);
@@ -241,13 +230,13 @@ public class ListUtil {
return UIUtil.getDeepestComponentAt(rendererComponent, rendererRelativeX, rendererRelativeY);
}
public static boolean canMoveSelectedItemsDown(JList list) {
public static <T> boolean canMoveSelectedItemsDown(@NotNull JList<T> list) {
ListModel model = list.getModel();
int[] indices = list.getSelectedIndices();
return indices.length > 0 && indices[indices.length - 1] < model.getSize() - 1;
}
public static Updatable addMoveUpListener(JButton button, final JList list) {
public static <T> Updatable addMoveUpListener(@NotNull JButton button, @NotNull JList<T> list) {
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -259,7 +248,7 @@ public class ListUtil {
}
public static Updatable addMoveDownListener(JButton button, final JList list) {
public static <T> Updatable addMoveDownListener(@NotNull JButton button, @NotNull JList<T> list) {
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -270,17 +259,20 @@ public class ListUtil {
return disableWhenNoSelection(button, list);
}
public static Updatable addRemoveListener(final JButton button, final JList list) {
public static <T> Updatable addRemoveListener(@NotNull JButton button, @NotNull JList<T> list) {
return addRemoveListener(button, list, null);
}
public static Updatable addRemoveListener(final JButton button, final JList list, final RemoveNotification<String> notification) {
public static <T> Updatable addRemoveListener(@NotNull JButton button,
@NotNull JList<T> list,
@Nullable RemoveNotification<T> notification) {
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
final List<String> items = removeSelectedItems(list);
if (notification != null)
List<T> items = removeSelectedItems(list);
if (notification != null) {
notification.itemsRemoved(items);
}
list.requestFocusInWindow();
}
});
@@ -305,15 +297,7 @@ public class ListUtil {
return listener;
}
private static Object get(ListModel model, int index) {
return getExtensions(model).get(model, index);
}
private static void remove(ListModel model, int index) {
getExtensions(model).remove(model, index);
}
public static Updatable disableWhenNoSelection(final JButton button, final JList list) {
public static <T> Updatable disableWhenNoSelection(@NotNull JButton button, @NotNull JList<T> list) {
class MyListSelectionListener extends Updatable implements ListSelectionListener {
MyListSelectionListener(JButton button) {
super(button);
@@ -339,67 +323,57 @@ public class ListUtil {
void itemsRemoved(List<ItemType> items);
}
private static ListModelExtension getExtensions(ListModel model) {
/**
* @noinspection unchecked
*/
@NotNull
private static <T, ModelType extends ListModel<T>> ListModelExtension<T, ModelType> getExtension(@NotNull ModelType model) {
if (model instanceof DefaultListModel) return DEFAULT_MODEL;
if (model instanceof SortedListModel) return SORTED_MODEL;
if (model instanceof FilteringListModel) return FILTERED_MODEL;
if (model instanceof CollectionListModel) return COLLECTION_MODEL;
if (model == null) LOG.assertTrue(false);
else LOG.error("Unknown model class: " + model.getClass().getName());
return null;
throw new AssertionError("Unknown model class: " + model.getClass().getName());
}
private interface ListModelExtension<ModelType extends ListModel> {
Object get(ModelType model, int index);
//@formatter:off
private interface ListModelExtension<T, ModelType extends ListModel<T>> {
T get(ModelType model, int index);
void set(ModelType model, int index, T item);
void remove(ModelType model, int index);
void removeAll(ModelType model);
void addAll(ModelType model, List<T> item);
}
private static final ListModelExtension DEFAULT_MODEL = new ListModelExtension<DefaultListModel>() {
@Override
public Object get(DefaultListModel model, int index) {
return model.get(index);
}
@Override
public void remove(DefaultListModel model, int index) {
model.remove(index);
}
private static final ListModelExtension DEFAULT_MODEL = new ListModelExtension<Object, DefaultListModel<Object>>() {
@Override public Object get(DefaultListModel<Object> model, int index) { return model.get(index);}
@Override public void set(DefaultListModel<Object> model, int index, Object item) { model.set(index, item);}
@Override public void remove(DefaultListModel<Object> model, int index) { model.remove(index);}
@Override public void removeAll(DefaultListModel<Object> model) { model.removeAllElements();}
@Override public void addAll(DefaultListModel<Object> model, List<Object> item) { model.addElement(item);}
};
private static final ListModelExtension COLLECTION_MODEL = new ListModelExtension<CollectionListModel>() {
@Override
public Object get(CollectionListModel model, int index) {
return model.getElementAt(index);
}
@Override
public void remove(CollectionListModel model, int index) {
model.remove(index);
}
private static final ListModelExtension COLLECTION_MODEL = new ListModelExtension<Object, CollectionListModel<Object>>() {
@Override public Object get(CollectionListModel<Object> model, int index) { return model.getElementAt(index);}
@Override public void set(CollectionListModel<Object> model, int index, Object item) { model.setElementAt(item, index);}
@Override public void remove(CollectionListModel<Object> model, int index) { model.remove(index);}
@Override public void removeAll(CollectionListModel<Object> model) { model.removeAll();}
@Override public void addAll(CollectionListModel<Object> model, List<Object> items) { model.addAll(model.getSize(), items);}
};
private static final ListModelExtension SORTED_MODEL = new ListModelExtension<SortedListModel>() {
@Override
public Object get(SortedListModel model, int index) {
return model.get(index);
}
@Override
public void remove(SortedListModel model, int index) {
model.remove(index);
}
private static final ListModelExtension SORTED_MODEL = new ListModelExtension<Object, SortedListModel<Object>>() {
@Override public Object get(SortedListModel<Object> model, int index) { return model.get(index);}
@Override public void set(SortedListModel<Object> model, int index, Object item) { model.remove(index); model.add(item);}
@Override public void remove(SortedListModel<Object> model, int index) { model.remove(index);}
@Override public void removeAll(SortedListModel<Object> model) { model.clear();}
@Override public void addAll(SortedListModel<Object> model, List<Object> items) { model.addAll(items);}
};
private static final ListModelExtension FILTERED_MODEL = new ListModelExtension<FilteringListModel>() {
@Override
public Object get(FilteringListModel model, int index) {
return model.getElementAt(index);
}
@Override
public void remove(FilteringListModel model, int index) {
model.remove(index);
}
private static final ListModelExtension FILTERED_MODEL = new ListModelExtension<Object, FilteringListModel<Object>>() {
@Override public Object get(FilteringListModel<Object> model, int index) { return model.getElementAt(index);}
@Override public void set(FilteringListModel<Object> model, int index, Object item) { getExtension(model.getOriginalModel()).set(model, index, item);}
@Override public void remove(FilteringListModel<Object> model, int index) { model.remove(index);}
@Override public void removeAll(FilteringListModel<Object> model) { model.replaceAll(Collections.emptyList());}
@Override public void addAll(FilteringListModel<Object> model, List<Object> items) { model.addAll(items);}
};
//@formatter:on
}
@@ -21,6 +21,8 @@ package com.intellij.ui.speedSearch;
import com.intellij.openapi.util.Condition;
import com.intellij.ui.CollectionListModel;
import com.intellij.ui.ListUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.event.ListDataEvent;
@@ -123,13 +125,13 @@ public class FilteringListModel<T> extends AbstractListModel<T> {
return myData.contains(value);
}
public ListModel getOriginalModel() {
@NotNull
public ListModel<T> getOriginalModel() {
return myOriginalModel;
}
public void addAll(List<T> elements) {
myData.addAll(elements);
((CollectionListModel<T>)myOriginalModel).add(elements);
ListUtil.addAllItems(myOriginalModel, elements);
}
public void replaceAll(List<T> elements) {
@@ -139,6 +141,6 @@ public class FilteringListModel<T> extends AbstractListModel<T> {
}
public void remove(int index) {
((CollectionListModel<T>)myOriginalModel).remove(myData.get(index));
ListUtil.removeItem(myOriginalModel, index);
}
}
@@ -26,7 +26,7 @@ import java.awt.*;
import java.awt.event.FocusEvent;
public class ListWithFilter<T> extends JPanel implements DataProvider {
private final JList<? extends T> myList;
private final JList<T> myList;
private final SearchTextField mySearchField = new SearchTextField(false);
private final NameFilteringListModel<T> myModel;
private final JScrollPane myScrollPane;
@@ -52,7 +52,7 @@ public class ListWithFilter<T> extends JPanel implements DataProvider {
return new ListWithFilter<>(list, scrollPane, namer, highlightAllOccurrences);
}
private ListWithFilter(@NotNull JList<? extends T> list,
private ListWithFilter(@NotNull JList<T> list,
@NotNull JScrollPane scrollPane,
@Nullable Function<? super T, String> namer,
boolean highlightAllOccurrences) {
@@ -77,7 +77,7 @@ public class ListWithFilter<T> extends JPanel implements DataProvider {
myList.addKeyListener(mySpeedSearch);
int selectedIndex = myList.getSelectedIndex();
int modelSize = myList.getModel().getSize();
myModel = new NameFilteringListModel<T>(myList, namer, mySpeedSearch::shouldBeShowing, mySpeedSearch);
myModel = new NameFilteringListModel<>(myList, namer, mySpeedSearch::shouldBeShowing, mySpeedSearch);
if (myModel.getSize() == modelSize) {
myList.setSelectedIndex(selectedIndex);
}
@@ -45,15 +45,15 @@ public class NameFilteringListModel<T> extends FilteringListModel<T> {
this(list, namer, filter, () -> speedSearch.getFilter());
}
public NameFilteringListModel(JList list, final Function<? super T, String> namer, final Condition<? super String> filter, final SpeedSearchSupply speedSearch) {
public NameFilteringListModel(JList<T> list, final Function<? super T, String> namer, final Condition<? super String> filter, final SpeedSearchSupply speedSearch) {
this(list, namer, filter, () -> {
final String prefix = speedSearch.getEnteredPrefix();
return prefix == null ? "" : prefix;
});
}
public NameFilteringListModel(JList list, final Function<? super T, String> namer, final Condition<? super String> filter, Computable<String> pattern) {
super(list);
public NameFilteringListModel(JList<T> list, final Function<? super T, String> namer, final Condition<? super String> filter, Computable<String> pattern) {
super(list.getModel());
myPattern = pattern;
myNamer = namer;
setFilter(namer != null ? (Condition<T>)t -> filter.value(namer.fun(t)) : null);