diff --git a/javafx-ui-controls/src/javafx/scene/control/ControlUtils.java b/javafx-ui-controls/src/javafx/scene/control/ControlUtils.java --- a/javafx-ui-controls/src/javafx/scene/control/ControlUtils.java +++ b/javafx-ui-controls/src/javafx/scene/control/ControlUtils.java @@ -3,18 +3,21 @@ import javafx.beans.InvalidationListener; import javafx.beans.Observable; import javafx.event.Event; +import javafx.event.EventType; import javafx.scene.Node; class ControlUtils { - private static final String CACHE_KEY = "util.scroll.index"; + private static final String ROW_KEY = "util.scroll.index"; + private static final String COL_KEY = "util.scroll.col"; + public static void scrollToIndex(final Node node, int index) { if( node.getScene() == null ) { - if( ! node.getProperties().containsKey(CACHE_KEY) ) { + if( ! node.getProperties().containsKey(ROW_KEY) ) { node.sceneProperty().addListener(new InvalidationListener() { @Override public void invalidated(Observable observable) { - Integer idx = (Integer) node.getProperties().remove(CACHE_KEY); + Integer idx = (Integer) node.getProperties().remove(ROW_KEY); if( idx != null ) { Event.fireEvent(node, new ScrollToEvent(node, node, ScrollToEvent.SCROLL_TO_TOP_INDEX, idx)); } @@ -22,9 +25,32 @@ } }); } - node.getProperties().put(CACHE_KEY, index); + node.getProperties().put(ROW_KEY, index); } else { Event.fireEvent(node, new ScrollToEvent(node, node, ScrollToEvent.SCROLL_TO_TOP_INDEX, index)); } } + + public static void scrollToColumn(final Node node, TableColumnBase column) { + if( node.getScene() == null ) { + if( ! node.getProperties().containsKey(COL_KEY) ) { + node.sceneProperty().addListener(new InvalidationListener() { + + @Override + public void invalidated(Observable observable) { + TableColumnBase col = (TableColumnBase) node.getProperties().remove(COL_KEY); + if( col != null ) { + EventType>> type = ScrollToEvent.scrollToColumn(); + Event.fireEvent(node, new ScrollToEvent>(node, node, type, col)); + } + node.sceneProperty().removeListener(this); + } + }); + } + node.getProperties().put(COL_KEY, column); + } else { + EventType>> type = ScrollToEvent.scrollToColumn(); + Event.fireEvent(node, new ScrollToEvent>(node, node, type, column)); + } + } } diff --git a/javafx-ui-controls/src/javafx/scene/control/ListView.java b/javafx-ui-controls/src/javafx/scene/control/ListView.java --- a/javafx-ui-controls/src/javafx/scene/control/ListView.java +++ b/javafx-ui-controls/src/javafx/scene/control/ListView.java @@ -726,7 +726,21 @@ } /** + * Scrolls the TableView so that the given object is visible within the viewport. + * @param object The object that should be visible to the user. + */ + public void scrollTo(T object) { + if( getItems() != null ) { + int idx = getItems().indexOf(object); + if( idx >= 0 ) { + ControlUtils.scrollToIndex(this, idx); + } + } + } + + /** * Called when there's a request to scroll an index into view using {@link #scrollTo(int)} + * or {@link #scrollTo(S)} */ private ObjectProperty>> onScrollTo; diff --git a/javafx-ui-controls/src/javafx/scene/control/ScrollToEvent.java b/javafx-ui-controls/src/javafx/scene/control/ScrollToEvent.java --- a/javafx-ui-controls/src/javafx/scene/control/ScrollToEvent.java +++ b/javafx-ui-controls/src/javafx/scene/control/ScrollToEvent.java @@ -22,7 +22,18 @@ */ public static final EventType> SCROLL_TO_TOP_INDEX = new EventType>(Event.ANY, "SCROLL_TO_TOP_INDEX"); - + + private static final EventType SCROLL_TO_COLUMN = + new EventType(Event.ANY, "SCROLL_TO_COLUMN"); + + /** + * @return event occurs if the user requests scrolling a given column into view + */ + @SuppressWarnings("unchecked") + public static > EventType> scrollToColumn() { + return (EventType>) SCROLL_TO_COLUMN; + } + private static final long serialVersionUID = -8557345736849482516L; private final T scrollTarget; diff --git a/javafx-ui-controls/src/javafx/scene/control/TableView.java b/javafx-ui-controls/src/javafx/scene/control/TableView.java --- a/javafx-ui-controls/src/javafx/scene/control/TableView.java +++ b/javafx-ui-controls/src/javafx/scene/control/TableView.java @@ -59,6 +59,7 @@ import javafx.collections.WeakListChangeListener; import javafx.event.Event; import javafx.event.EventHandler; +import javafx.event.EventType; import com.sun.javafx.scene.control.skin.TableViewSkin; import com.sun.javafx.scene.control.skin.TableViewSkinBase; @@ -863,7 +864,21 @@ } /** + * Scrolls the TableView so that the given object is visible within the viewport. + * @param object The object that should be visible to the user. + */ + public void scrollTo(S object) { + if( getItems() != null ) { + int idx = getItems().indexOf(object); + if( idx >= 0 ) { + ControlUtils.scrollToIndex(this, idx); + } + } + } + + /** * Called when there's a request to scroll an index into view using {@link #scrollTo(int)} + * or {@link #scrollTo(Object)} */ private ObjectProperty>> onScrollTo; @@ -898,7 +913,64 @@ } return onScrollTo; } + + /** + * Scrolls the TableView so that the given column is visible within the viewport. + * @param column The column that should be visible to the user. + */ + public void scrollToColumn(TableColumn column) { + ControlUtils.scrollToColumn(this, column); + } + + /** + * Scrolls the TableView so that the given index is visible within the viewport. + * @param columnIndex The index of a column that should be visible to the user. + */ + public void scrollToColumnIndex(int columnIndex) { + if( getColumns() != null ) { + ControlUtils.scrollToColumn(this, getColumns().get(columnIndex)); + } + } + + /** + * Called when there's a request to scroll a column into view using {@link #scrollToColumn(TableColumn)} + * or {@link #scrollToColumnIndex(int)} + */ + private ObjectProperty>>> onScrollToColumn; + + public void setOnScrollToColumn(EventHandler>> value) { + onScrollToColumnProperty().set(value); + } + + public EventHandler>> getOnScrollToColumn() { + if( onScrollToColumn != null ) { + return onScrollToColumn.get(); + } + return null; + } + + public ObjectProperty>>> onScrollToColumnProperty() { + if( onScrollToColumn == null ) { + onScrollToColumn = new ObjectPropertyBase>>>() { + @Override + protected void invalidated() { + EventType>> type = ScrollToEvent.scrollToColumn(); + setEventHandler(type, get()); + } + @Override + public Object getBean() { + return TableView.this; + } + @Override + public String getName() { + return "onScrollToColumn"; + } + }; + } + return onScrollToColumn; + } + /** * Applies the currently installed resize policy against the given column, * resizing it based on the delta value provided. diff --git a/javafx-ui-controls/src/javafx/scene/control/TreeTableView.java b/javafx-ui-controls/src/javafx/scene/control/TreeTableView.java --- a/javafx-ui-controls/src/javafx/scene/control/TreeTableView.java +++ b/javafx-ui-controls/src/javafx/scene/control/TreeTableView.java @@ -1285,6 +1285,63 @@ } /** + * Scrolls the TreeTableView so that the given column is visible within the viewport. + * @param column The column that should be visible to the user. + */ + public void scrollToColumn(TableColumn column) { + ControlUtils.scrollToColumn(this, column); + } + + /** + * Scrolls the TreeTableView so that the given index is visible within the viewport. + * @param columnIndex The index of a column that should be visible to the user. + */ + public void scrollToColumnIndex(int columnIndex) { + if( getColumns() != null ) { + ControlUtils.scrollToColumn(this, getColumns().get(columnIndex)); + } + } + + /** + * Called when there's a request to scroll a column into view using {@link #scrollToColumn(TableColumn)} + * or {@link #scrollToColumnIndex(int)} + */ + private ObjectProperty>>> onScrollToColumn; + + public void setOnScrollToColumn(EventHandler>> value) { + onScrollToColumnProperty().set(value); + } + + public EventHandler>> getOnScrollToColumn() { + if( onScrollToColumn != null ) { + return onScrollToColumn.get(); + } + return null; + } + + public ObjectProperty>>> onScrollToColumnProperty() { + if( onScrollToColumn == null ) { + onScrollToColumn = new ObjectPropertyBase>>>() { + @Override + protected void invalidated() { + EventType>> type = ScrollToEvent.scrollToColumn(); + setEventHandler(type, get()); + } + @Override + public Object getBean() { + return TreeTableView.this; + } + + @Override + public String getName() { + return "onScrollToColumn"; + } + }; + } + return onScrollToColumn; + } + + /** * Returns the index position of the given TreeItem, taking into account the * current state of each TreeItem (i.e. whether or not it is expanded). *