Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.scene.control; 027 028import java.util.List; 029import javafx.beans.property.ReadOnlyObjectProperty; 030import javafx.beans.property.ReadOnlyObjectWrapper; 031import javafx.collections.ListChangeListener.Change; 032import javafx.collections.ObservableList; 033import com.sun.javafx.collections.VetoableListDecorator; 034import com.sun.javafx.collections.TrackableObservableList; 035 036/** 037 * A class which contains a reference to all {@code Toggles} whose 038 * {@code selected} variables should be managed such that only a single 039 * <code>{@link Toggle}</code> within the {@code ToggleGroup} may be selected at 040 * any one time. 041 * <p> 042 * Generally {@code ToggleGroups} are managed automatically simply by specifying 043 * the name of a {@code ToggleGroup} on the <code>{@link Toggle}</code>, but in 044 * some situations it is desirable to explicitly manage which 045 * {@code ToggleGroup} is used by <code>{@link Toggle Toggles}</code>. 046 * </p> 047 */ 048public class ToggleGroup { 049 /** 050 * The list of toggles within the ToggleGroup. 051 */ 052 public final ObservableList<Toggle> getToggles() { 053 return toggles; 054 } 055 056 private final ObservableList<Toggle> toggles = new VetoableListDecorator<Toggle>(new TrackableObservableList<Toggle>() { 057 @Override protected void onChanged(Change<Toggle> c) { 058 while (c.next()) { 059 // Look through the removed toggles, and if any of them was the 060 // one and only selected toggle, then we will clear the selected 061 // toggle property. 062 for (Toggle t : c.getRemoved()) { 063 if (t.isSelected()) { 064 selectToggle(null); 065 } 066 } 067 068 // A Toggle can only be in one group at any one time. If the 069 // group is changed, then the toggle is removed from the old group prior to 070 // being added to the new group. 071 for (Toggle t: c.getAddedSubList()) { 072 if (!ToggleGroup.this.equals(t.getToggleGroup())) { 073 if (t.getToggleGroup() != null) { 074 t.getToggleGroup().getToggles().remove(t); 075 } 076 t.setToggleGroup(ToggleGroup.this); 077 } 078 } 079 080 // Look through all the added toggles and the very first selected 081 // toggle we encounter will become the one we make the selected 082 // toggle for this group. 083 for (Toggle t : c.getAddedSubList()) { 084 if (t.isSelected()) { 085 selectToggle(t); 086 break; 087 } 088 } 089 } 090 } 091 }) { 092 @Override protected void onProposedChange(List<Toggle> toBeAdded, int... indexes) { 093 for (Toggle t: toBeAdded) { 094 if (indexes[0] == 0 && indexes[1] == size()) { 095 // we don't need to check for duplicates because this is a setAll. 096 break; 097 } 098 if (toggles.contains(t)) { 099 throw new IllegalArgumentException("Duplicate toggles are not allow in a ToggleGroup."); 100 } 101 } 102 } 103 }; 104 105 private final ReadOnlyObjectWrapper<Toggle> selectedToggle = new ReadOnlyObjectWrapper<Toggle>() { 106 // Note: "set" is really what I want here. If the selectedToggle property 107 // is bound, then this whole chunk of code is bypassed, which is exactly 108 // what I want to do. 109 @Override public void set(final Toggle newSelectedToggle) { 110 if (isBound()) { 111 throw new java.lang.RuntimeException("A bound value cannot be set."); 112 } 113 final Toggle old = get(); 114 if (setSelected(newSelectedToggle, true) || 115 (newSelectedToggle != null && newSelectedToggle.getToggleGroup() == ToggleGroup.this) || 116 (newSelectedToggle == null)) { 117 if (old == null || old.getToggleGroup() == ToggleGroup.this || !old.isSelected()) { 118 setSelected(old, false); 119 } 120 super.set(newSelectedToggle); 121 } 122 } 123 }; 124 125 /** 126 * Selects the toggle. 127 * 128 * @param value The {@code Toggle} that is to be selected. 129 */ 130 // Note that since selectedToggle is a read-only property, the selectToggle method is some 131 // other method than setSelectedToggle, even though it is in essence doing the same thing 132 public final void selectToggle(Toggle value) { selectedToggle.set(value); } 133 134 /** 135 * Gets the selected {@code Toggle}. 136 * @return Toggle The selected toggle. 137 */ 138 public final Toggle getSelectedToggle() { return selectedToggle.get(); } 139 140 /** 141 * The selected toggle. 142 */ 143 public final ReadOnlyObjectProperty<Toggle> selectedToggleProperty() { return selectedToggle.getReadOnlyProperty(); } 144 145 private boolean setSelected(Toggle toggle, boolean selected) { 146 if (toggle != null && 147 toggle.getToggleGroup() == this && 148 !toggle.selectedProperty().isBound()) { 149 toggle.setSelected(selected); 150 return true; 151 } 152 return false; 153 } 154 155 // Clear the selected toggle only if there are no other toggles selected. 156 final void clearSelectedToggle() { 157 if (!selectedToggle.getValue().isSelected()) { 158 for (Toggle toggle: getToggles()) { 159 if (toggle.isSelected()) { 160 return; 161 } 162 } 163 } 164 selectedToggle.set(null); 165 } 166}