/* * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package javafx.scene.control; import com.sun.javafx.scene.control.skin.Utils; import javafx.beans.InvalidationListener; import javafx.beans.Observable; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import javafx.collections.ObservableMap; import javafx.event.Event; import javafx.scene.Node; import javafx.scene.Parent; import javafx.scene.Scene; import java.util.List; 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>(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 ListChangeListener.Change buildClearAndSelectChange( ObservableList list, List removed, int retainedRow) { return new ListChangeListener.Change(list) { private final int[] EMPTY_PERM = new int[0]; private final int removedSize = removed.size(); private final List firstRemovedRange; private final List 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 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; // point 'from' to the first position, relative to // the underlying selectedCells index. from = 0; return true; } if (atFirstRange && !secondRemovedRange.isEmpty()) { atFirstRange = false; // point 'from' to the second position, relative to // the underlying selectedCells index. 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."); } } }; } }