package javafx.scene.control;
import com.sun.javafx.scene.control.skin.Utils;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.Event;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
class ControlUtils {
private ControlUtils() { }
public static void scrollToIndex(final Control control, int index) {
Utils.executeOnceWhenPropertyIsNonNull(control.skinProperty(), (Skin<?> skin) -> {
Event.fireEvent(control, new ScrollToEvent<>(control, control, ScrollToEvent.scrollToTopIndex(), index));
});
}
public static void scrollToColumn(final Control control, final TableColumnBase<?, ?> column) {
Utils.executeOnceWhenPropertyIsNonNull(control.skinProperty(), (Skin<?> skin) -> {
control.fireEvent(new ScrollToEvent<TableColumnBase<?, ?>>(control, control, ScrollToEvent.scrollToColumn(), column));
});
}
static void requestFocusOnControlOnlyIfCurrentFocusOwnerIsChild(Control c) {
Scene scene = c.getScene();
final Node focusOwner = scene == null ? null : scene.getFocusOwner();
if (focusOwner == null) {
c.requestFocus();
} else if (! c.equals(focusOwner)) {
Parent p = focusOwner.getParent();
while (p != null) {
if (c.equals(p)) {
c.requestFocus();
break;
}
p = p.getParent();
}
}
}
static <T> ListChangeListener.Change<T> buildClearAndSelectChange(
ObservableList<T> list, List<T> removed, int retainedRow) {
return new ListChangeListener.Change<T>(list) {
private final int[] EMPTY_PERM = new int[0];
private final int removedSize = removed.size();
private final List<T> firstRemovedRange;
private final List<T> secondRemovedRange;
private boolean invalid = true;
private boolean atFirstRange = true;
private int from = -1;
{
int midIndex = retainedRow >= removedSize ? removedSize :
retainedRow < 0 ? 0 :
retainedRow;
firstRemovedRange = removed.subList(0, midIndex);
secondRemovedRange = removed.subList(midIndex, removedSize);
}
@Override public int getFrom() {
checkState();
return from;
}
@Override public int getTo() {
return getFrom();
}
@Override public List<T> getRemoved() {
checkState();
return atFirstRange ? firstRemovedRange : secondRemovedRange;
}
@Override public int getRemovedSize() {
return atFirstRange ? firstRemovedRange.size() : secondRemovedRange.size();
}
@Override protected int[] getPermutation() {
checkState();
return EMPTY_PERM;
}
@Override public boolean next() {
if (invalid && atFirstRange) {
invalid = false;
from = 0;
return true;
}
if (atFirstRange && !secondRemovedRange.isEmpty()) {
atFirstRange = false;
from = 1;
return true;
}
return false;
}
@Override public void reset() {
invalid = true;
atFirstRange = true;
}
private void checkState() {
if (invalid) {
throw new IllegalStateException("Invalid Change state: next() must be called before inspecting the Change.");
}
}
};
}
public static <S> void updateSelectedIndices(MultipleSelectionModelBase<S> sm, ListChangeListener.Change<? extends TablePositionBase<?>> c) {
sm.selectedIndices._beginChange();
while (c.next()) {
sm.startAtomic();
final List<Integer> removed = c.getRemoved().stream()
.map(TablePositionBase::getRow)
.distinct()
.peek(sm.selectedIndices::clear)
.collect(Collectors.toList());
final int addedSize = (int)c.getAddedSubList().stream()
.map(TablePositionBase::getRow)
.distinct()
.peek(sm.selectedIndices::set)
.count();
sm.stopAtomic();
final int to = c.getFrom() + addedSize;
if (c.wasReplaced()) {
sm.selectedIndices._nextReplace(c.getFrom(), to, removed);
} else if (c.wasRemoved()) {
sm.selectedIndices._nextRemove(c.getFrom(), removed);
} else if (c.wasAdded()) {
sm.selectedIndices._nextAdd(c.getFrom(), to);
}
}
c.reset();
sm.selectedIndices.reset();
if (sm.isAtomic()) {
return;
}
if (sm.getSelectedItems().isEmpty() && sm.getSelectedItem() != null) {
sm.setSelectedItem(null);
}
sm.selectedIndices._endChange();
}
static void reducingChange(MultipleSelectionModelBase<?>.SelectedIndicesList selectedIndices, List<Integer> removed) {
if (removed.isEmpty()) return;
int startPos = 0;
int endPos = 1;
boolean firedOnce = false;
while (endPos < removed.size()) {
if (removed.get(startPos) == removed.get(endPos) - 1) {
endPos++;
continue;
}
selectedIndices._nextRemove(selectedIndices.indexOf(removed.get(startPos)), removed.subList(startPos, endPos));
startPos = endPos;
endPos = startPos + 1;
firedOnce = true;
}
if (!firedOnce) {
selectedIndices._nextRemove(selectedIndices.indexOf(removed.get(0)), removed);
}
}
}