MultipleSelectionModel: какой список изменений событий ожидать от selectedIndices?
... в частности, при изменении базовых элементов?
Ниже приведен быстрый пример, который выбирает диапазон и добавляет элемент над выбором для TableView и ListView. Выбранные идентификаторы до / после добавления:
indices before modification: [2, 3]
indices after modification: [3, 4]
Ожидаемые варианты:
- один был заменен на весь диапазон
- wasRemoved для "2" и wasAdded для "4"
- ??
Актуально:
- выбор таблицы запускает два события, каждое с одним wasAdded
- выбор списка запускает wasPermutated (это чокнутый, или что я пропускаю?)
Выход (jdk8u40b12):
Change #0 on TableView indices
list = [3]
Change event data:
class javafx.scene.control.MultipleSelectionModelBase$3
javafx.scene.control.MultipleSelectionModelBase$3@4ececa
cursor = 0
Kind of change: added
Affected range: [0, 1]
Added size: 1
Added sublist: [3]
Change #1 on TableView indices
list = [3, 4]
Change event data:
class javafx.scene.control.MultipleSelectionModelBase$3
javafx.scene.control.MultipleSelectionModelBase$3@b0161d
cursor = 0
Kind of change: added
Affected range: [1, 2]
Added size: 1
Added sublist: [4]
Change #0 on ListView indices
list = [3, 4]
Change event data:
class com.sun.javafx.collections.NonIterableChange$SimplePermutationChange
{ permutated by [4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0] }
cursor = 0
Kind of change: permutated
Affected range: [0, 2]
Permutation: [0->4, 1->3]
Производящий код:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.ListChangeListener.Change;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
public class SelectedIndicesOnItemsModified extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
ObservableList<Integer> items = FXCollections.observableArrayList(1, 2, 3, 4);
TableView<Integer> table = new TableView<>(items);
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
table.getSelectionModel().selectRange(2, 4);
System.out.println("indices before modification: " +
table.getSelectionModel().getSelectedIndices());
ListView<Integer> list = new ListView<>(items);
list.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
list.getSelectionModel().selectRange(2, 4);
new PrintingListChangeListener("TableView indices ",
table.getSelectionModel().getSelectedIndices());
new PrintingListChangeListener("ListView indices ",
list.getSelectionModel().getSelectedIndices());
items.add(0, 111);
}
public static void main(String[] args) {
launch(args);
}
public static <T> void prettyPrint(Change<? extends T> change) {
StringBuilder sb = new StringBuilder("\tChange event data:\n");
sb.append("\n " + change.getClass() + "\n " + change);
int i = 0;
change.reset();
while (change.next()) {
sb.append("\n\tcursor = ").append(i++).append("\n");
final String kind = change.wasPermutated() ? "permutated" : change
.wasReplaced() ? "replaced"
: change.wasRemoved() ? "removed"
: change.wasAdded() ? "added"
: change.wasUpdated() ? "updated" : "none";
sb.append("\t\tKind of change: ").append(kind).append("\n");
sb.append("\t\tAffected range: [").append(change.getFrom())
.append(", ").append(change.getTo()).append("]\n");
if (kind.equals("added") || kind.equals("replaced")) {
sb.append("\t\tAdded size: ").append(change.getAddedSize())
.append("\n");
sb.append("\t\tAdded sublist: ")
.append(change.getAddedSubList()).append("\n");
}
if (kind.equals("removed") || kind.equals("replaced")) {
sb.append("\t\tRemoved size: ").append(change.getRemovedSize())
.append("\n");
sb.append("\t\tRemoved: ").append(change.getRemoved())
.append("\n");
}
if (kind.equals("permutated")) {
StringBuilder permutationStringBuilder = new StringBuilder("[");
for (int k = change.getFrom(); k < change.getTo(); k++) {
permutationStringBuilder.append(k).append("->")
.append(change.getPermutation(k));
if (k < change.getTo() - 1) {
permutationStringBuilder.append(", ");
}
}
permutationStringBuilder.append("]");
String permutation = permutationStringBuilder.toString();
sb.append("\t\tPermutation: ").append(permutation).append("\n");
}
}
System.out.println(sb.toString());
};
public static class PrintingListChangeListener implements ListChangeListener {
String source;
int counter;
public PrintingListChangeListener() {
}
public PrintingListChangeListener(String message, ObservableList<?> list) {
list.addListener(this);
source = message;
}
@Override
public void onChanged(Change change) {
System.out.println("Change #" + counter++ + " on " +source +
"\nlist = " + change.getList());
prettyPrint(change);
}
}
}
Поданы две проблемы, RT-39393 для ListView, RT-39394 для TableView
1 ответ
Предварительный частично ответ на мой собственный вопрос
Количество уведомлений
Номер уведомления (он же: вызовы к изменению (Изменить c)) должен совпадать с номером в базовых данных в псевдокоде.
itemsChanges = 0;
itemsListener = c -> itemsChanges++;
getItems().addListener(itemsListener);
selectedChanges = 0;
selectedListener = c -> selectedChanges++;
getSelectedIndices().addListener(selectedListener);
getItems().modifySomehow(...);
assertEquals(itemsChanges, selectedChanges);
Изменить типы
Думая об этом, большинство изменений в базовых элементах, кажется, отображаются на замененные в selectedIndices ("value" ниже обозначает элементы в selectedIndices):
"реальный" wasAdded: все значения, превышающие положение вставки, должны быть увеличены при добавлении размера
// selectedIndices before
[2, 4]
items.add(0, something);
// selectedIndices after
[3, 5]
-> Чистый эффект: два значения устанавливаются (== заменяется на) новым значением
"реальный" wasRemoved: все значения, указывающие на удаленные элементы, также должны быть удалены, значения, которые больше, чем местоположение удаления, должны быть уменьшены при удалении
// selectedIndices before
[2, 4, 5, 8]
items.removeAll(items.get(3), items.get(5))
// selectedIndices after
[2, 3, 6]
-> Чистый эффект: заменить [4, 5, 8] в поз. 1 на [3, 6]
wasUpdated: индексы не изменились, хотя базовые элементы как-то изменились. В зависимости от контекста, может быть хорошей идеей передать эти обновления своему слушателю или нет.
Все еще открыто: заменено / перестановка в элементах
Чтобы получить ожидаемые (по крайней мере, по моей бумажной кодировке:-) уведомления правильные, не совсем тривиальные - и пошли не так в MultipleSelectionModelBase и подклассах. В настоящее время играет с перемещением всех неприятных деталей в отдельный IndicesList (который является TransformList с элементами в качестве sourceList).