/* * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javafx.scene.control; /** * A SelectionModel which enforces the requirement that only a single index * be selected at any given time. This class exists for controls that allow for * pluggable selection models, but which do not allow for multiple selection. * A good example is the {@link ChoiceBox} control. Conversely, most other * controls ({@link ListView}, {@link TreeView}, {@link TableView}, etc) * require {@link MultipleSelectionModel} implementations (although * MultipleSelectionModel does still allow for single selection to be set via the * {@link MultipleSelectionModel#selectionModeProperty() selectionMode} * property). * * @see SelectionModel * @see MultipleSelectionModel * @see SelectionMode * @param The type of the item contained in the control that can be selected. * @since JavaFX 2.0 */ public abstract class SingleSelectionModel extends SelectionModel { /*************************************************************************** * * * Constructor * * * **************************************************************************/ /** * Creates a default SingleSelectionModel instance. */ public SingleSelectionModel() { } /*************************************************************************** * * * Selection API * * * **************************************************************************/ /** {@inheritDoc} */ @Override public void clearSelection() { updateSelectedIndex(-1); } /** * Clears the selection of the given index, if it is currently selected. */ @Override public void clearSelection(int index) { if (getSelectedIndex() == index) { clearSelection(); } } /** {@inheritDoc} */ @Override public boolean isEmpty() { return getItemCount() == 0 || getSelectedIndex() == -1; } /** *

This method will return true if the given index is the currently * selected index in this SingleSelectionModel. * * @param index The index to check as to whether it is currently selected * or not. * @return True if the given index is selected, false otherwise. */ @Override public boolean isSelected(int index) { return getSelectedIndex() == index; } /** * In the SingleSelectionModel, this method is functionally equivalent to * calling select(index), as only one selection is allowed at * a time. */ @Override public void clearAndSelect(int index) { select(index); } /** * Selects the index for the first instance of given object in the underlying * data model. Since the SingleSelectionModel can * only support having a single index selected at a time, this also causes * any previously selected index to be unselected. */ @Override public void select(T obj) { if (obj == null) { setSelectedIndex(-1); setSelectedItem(null); return; } final int itemCount = getItemCount(); for (int i = 0; i < itemCount; i++) { final T value = getModelItem(i); if (value != null && value.equals(obj)) { select(i); return; } } // if we are here, we did not find the item in the entire data model. // Even still, we allow for this item to be set to the give object. // We expect that in concrete subclasses of this class we observe the // data model such that we check to see if the given item exists in it, // whilst SelectedIndex == -1 && SelectedItem != null. setSelectedItem(obj); } /** * Selects the given index. Since the SingleSelectionModel can only support having * a single index selected at a time, this also causes any previously selected * index to be unselected. */ @Override public void select(int index) { if (index == -1) { clearSelection(); return; } final int itemCount = getItemCount(); if (itemCount == 0 || index < 0 || index >= itemCount) return; updateSelectedIndex(index); } /** * Selects the previous index. Since the SingleSelectionModel can only support having * a single index selected at a time, this also causes any previously selected * index to be unselected. */ @Override public void selectPrevious() { if (getSelectedIndex() == 0) return; select(getSelectedIndex() - 1); } /** * Selects the next index. Since the SingleSelectionModel can only support having * a single index selected at a time, this also causes any previously selected * index to be unselected. */ @Override public void selectNext() { select(getSelectedIndex() + 1); } /** * Selects the first index. Since the SingleSelectionModel can only support having * a single index selected at a time, this also causes any previously selected * index to be unselected. */ @Override public void selectFirst() { if (getItemCount() > 0) { select(0); } } /** * Selects the last index. Since the SingleSelectionModel can only support having * a single index selected at a time, this also causes any previously selected * index to be unselected. */ @Override public void selectLast() { int numItems = getItemCount(); if (numItems > 0 && getSelectedIndex() < numItems - 1) { select(numItems - 1); } } /** * Gets the data model item associated with a specific index. * @param index The position of the item in the underlying data model. * @return The item that exists at the given index. */ protected abstract T getModelItem(int index); /** * Gets the number of items available for the selection model. If the number * of items can change dynamically, it is the responsibility of the * concrete SingleSelectionModel implementation to ensure that items are * selected or unselected as appropriate as the items change. * @return A number greater than or equal to 0. */ protected abstract int getItemCount(); // Private Implementation private void updateSelectedIndex(int newIndex) { int currentIndex = getSelectedIndex(); T currentItem = getSelectedItem(); setSelectedIndex(newIndex); if (currentIndex == -1 && currentItem != null && newIndex == -1) { // no-op: the current selection isn't in the underlying data model - // we should keep the selected item as the new index is -1 } else { // we don't use newIndex here, to prevent RT-32139 (which has a unit // test developed to prevent regressions in the future) setSelectedItem(getModelItem(getSelectedIndex())); } } }