1 /* 2 * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.swing.text; 27 28 import java.io.Serializable; 29 30 /** 31 * A TabSet is comprised of many TabStops. It offers methods for locating the 32 * closest TabStop to a given position and finding all the potential TabStops. 33 * It is also immutable. 34 * <p> 35 * <strong>Warning:</strong> 36 * Serialized objects of this class will not be compatible with 37 * future Swing releases. The current serialization support is 38 * appropriate for short term storage or RMI between applications running 39 * the same version of Swing. As of 1.4, support for long term storage 40 * of all JavaBeans 41 * has been added to the <code>java.beans</code> package. 42 * Please see {@link java.beans.XMLEncoder}. 43 * 44 * @author Scott Violet 45 */ 46 @SuppressWarnings("serial") // Same-version serialization only 47 public class TabSet implements Serializable 48 { 49 /** TabStops this TabSet contains. */ 50 private TabStop[] tabs; 51 /** 52 * Since this class is immutable the hash code could be 53 * calculated once. MAX_VALUE means that it was not initialized 54 * yet. Hash code shouldn't has MAX_VALUE value. 55 */ 56 private int hashCode = Integer.MAX_VALUE; 57 58 /** 59 * Creates and returns an instance of TabSet. The array of Tabs 60 * passed in must be sorted in ascending order. 61 * @param tabs the TabStops to initialize the TabSet 62 */ TabSet(TabStop[] tabs)63 public TabSet(TabStop[] tabs) { 64 // PENDING(sky): If this becomes a problem, make it sort. 65 if(tabs != null) { 66 int tabCount = tabs.length; 67 68 this.tabs = new TabStop[tabCount]; 69 System.arraycopy(tabs, 0, this.tabs, 0, tabCount); 70 } 71 else 72 this.tabs = null; 73 } 74 75 /** 76 * Returns the number of Tab instances the receiver contains. 77 * @return the number of Tab instances the receiver contains 78 */ getTabCount()79 public int getTabCount() { 80 return (tabs == null) ? 0 : tabs.length; 81 } 82 83 /** 84 * Returns the TabStop at index <code>index</code>. This will throw an 85 * IllegalArgumentException if <code>index</code> is outside the range 86 * of tabs. 87 * @param index which TapStop to return 88 * @return the TabStop at index {@code index} 89 */ getTab(int index)90 public TabStop getTab(int index) { 91 int numTabs = getTabCount(); 92 93 if(index < 0 || index >= numTabs) 94 throw new IllegalArgumentException(index + 95 " is outside the range of tabs"); 96 return tabs[index]; 97 } 98 99 /** 100 * Returns the Tab instance after <code>location</code>. This will 101 * return null if there are no tabs after <code>location</code>. 102 * @param location location to find a Tab after 103 * @return the Tab instance after {@code location} 104 */ getTabAfter(float location)105 public TabStop getTabAfter(float location) { 106 int index = getTabIndexAfter(location); 107 108 return (index == -1) ? null : tabs[index]; 109 } 110 111 /** 112 * Returns the index of the TabStop <code>tab</code>, or -1 if 113 * <code>tab</code> is not contained in the receiver. 114 * @param tab the TabStop to find 115 * @return the index of the TabStop <code>tab</code>, or -1 if 116 * <code>tab</code> is not contained in the receiver. 117 */ getTabIndex(TabStop tab)118 public int getTabIndex(TabStop tab) { 119 for(int counter = getTabCount() - 1; counter >= 0; counter--) 120 // should this use .equals? 121 if(getTab(counter) == tab) 122 return counter; 123 return -1; 124 } 125 126 /** 127 * Returns the index of the Tab to be used after <code>location</code>. 128 * This will return -1 if there are no tabs after <code>location</code>. 129 * @param location location to find a Tab after 130 * @return the index of the Tab to be used after <code>location</code> 131 */ getTabIndexAfter(float location)132 public int getTabIndexAfter(float location) { 133 int current, min, max; 134 135 min = 0; 136 max = getTabCount(); 137 while(min != max) { 138 current = (max - min) / 2 + min; 139 if(location > tabs[current].getPosition()) { 140 if(min == current) 141 min = max; 142 else 143 min = current; 144 } 145 else { 146 if(current == 0 || location > tabs[current - 1].getPosition()) 147 return current; 148 max = current; 149 } 150 } 151 // no tabs after the passed in location. 152 return -1; 153 } 154 155 /** 156 * Indicates whether this <code>TabSet</code> is equal to another one. 157 * @param o the <code>TabSet</code> instance which this instance 158 * should be compared to. 159 * @return <code>true</code> if <code>o</code> is the instance of 160 * <code>TabSet</code>, has the same number of <code>TabStop</code>s 161 * and they are all equal, <code>false</code> otherwise. 162 * 163 * @since 1.5 164 */ equals(Object o)165 public boolean equals(Object o) { 166 if (o == this) { 167 return true; 168 } 169 if (o instanceof TabSet) { 170 TabSet ts = (TabSet) o; 171 int count = getTabCount(); 172 if (ts.getTabCount() != count) { 173 return false; 174 } 175 for (int i=0; i < count; i++) { 176 TabStop ts1 = getTab(i); 177 TabStop ts2 = ts.getTab(i); 178 if ((ts1 == null && ts2 != null) || 179 (ts1 != null && !getTab(i).equals(ts.getTab(i)))) { 180 return false; 181 } 182 } 183 return true; 184 } 185 return false; 186 } 187 188 /** 189 * Returns a hashcode for this set of TabStops. 190 * @return a hashcode value for this set of TabStops. 191 * 192 * @since 1.5 193 */ hashCode()194 public int hashCode() { 195 if (hashCode == Integer.MAX_VALUE) { 196 hashCode = 0; 197 int len = getTabCount(); 198 for (int i = 0; i < len; i++) { 199 TabStop ts = getTab(i); 200 hashCode ^= ts != null ? getTab(i).hashCode() : 0; 201 } 202 if (hashCode == Integer.MAX_VALUE) { 203 hashCode -= 1; 204 } 205 } 206 return hashCode; 207 } 208 209 /** 210 * Returns the string representation of the set of tabs. 211 */ toString()212 public String toString() { 213 int tabCount = getTabCount(); 214 StringBuilder buffer = new StringBuilder("[ "); 215 216 for(int counter = 0; counter < tabCount; counter++) { 217 if(counter > 0) 218 buffer.append(" - "); 219 buffer.append(getTab(counter).toString()); 220 } 221 buffer.append(" ]"); 222 return buffer.toString(); 223 } 224 } 225