1. /*
  2. * @(#)TabSet.java 1.15 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.text;
  8. import java.io.Serializable;
  9. /**
  10. * A TabSet is comprised of many TabStops. It offers methods for locating the
  11. * closest TabStop to a given position and finding all the potential TabStops.
  12. * It is also immutable.
  13. * <p>
  14. * <strong>Warning:</strong>
  15. * Serialized objects of this class will not be compatible with
  16. * future Swing releases. The current serialization support is
  17. * appropriate for short term storage or RMI between applications running
  18. * the same version of Swing. As of 1.4, support for long term storage
  19. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  20. * has been added to the <code>java.beans</code> package.
  21. * Please see {@link java.beans.XMLEncoder}.
  22. *
  23. * @author Scott Violet
  24. * @version 1.15 12/19/03
  25. */
  26. public class TabSet implements Serializable
  27. {
  28. /** TabStops this TabSet contains. */
  29. private TabStop[] tabs;
  30. /**
  31. * Since this class is immutable the hash code could be
  32. * calculated once. MAX_VALUE means that it was not initialized
  33. * yet. Hash code shouldn't has MAX_VALUE value.
  34. */
  35. private int hashCode = Integer.MAX_VALUE;
  36. /**
  37. * Creates and returns an instance of TabSet. The array of Tabs
  38. * passed in must be sorted in ascending order.
  39. */
  40. public TabSet(TabStop[] tabs) {
  41. // PENDING(sky): If this becomes a problem, make it sort.
  42. if(tabs != null) {
  43. int tabCount = tabs.length;
  44. this.tabs = new TabStop[tabCount];
  45. System.arraycopy(tabs, 0, this.tabs, 0, tabCount);
  46. }
  47. else
  48. this.tabs = null;
  49. }
  50. /**
  51. * Returns the number of Tab instances the receiver contains.
  52. */
  53. public int getTabCount() {
  54. return (tabs == null) ? 0 : tabs.length;
  55. }
  56. /**
  57. * Returns the TabStop at index <code>index</code>. This will throw an
  58. * IllegalArgumentException if <code>index</code> is outside the range
  59. * of tabs.
  60. */
  61. public TabStop getTab(int index) {
  62. int numTabs = getTabCount();
  63. if(index < 0 || index >= numTabs)
  64. throw new IllegalArgumentException(index +
  65. " is outside the range of tabs");
  66. return tabs[index];
  67. }
  68. /**
  69. * Returns the Tab instance after <code>location</code>. This will
  70. * return null if there are no tabs after <code>location</code>.
  71. */
  72. public TabStop getTabAfter(float location) {
  73. int index = getTabIndexAfter(location);
  74. return (index == -1) ? null : tabs[index];
  75. }
  76. /**
  77. * @return the index of the TabStop <code>tab</code>, or -1 if
  78. * <code>tab</code> is not contained in the receiver.
  79. */
  80. public int getTabIndex(TabStop tab) {
  81. for(int counter = getTabCount() - 1; counter >= 0; counter--)
  82. // should this use .equals?
  83. if(getTab(counter) == tab)
  84. return counter;
  85. return -1;
  86. }
  87. /**
  88. * Returns the index of the Tab to be used after <code>location</code>.
  89. * This will return -1 if there are no tabs after <code>location</code>.
  90. */
  91. public int getTabIndexAfter(float location) {
  92. int current, min, max;
  93. min = 0;
  94. max = getTabCount();
  95. while(min != max) {
  96. current = (max - min) / 2 + min;
  97. if(location > tabs[current].getPosition()) {
  98. if(min == current)
  99. min = max;
  100. else
  101. min = current;
  102. }
  103. else {
  104. if(current == 0 || location > tabs[current - 1].getPosition())
  105. return current;
  106. max = current;
  107. }
  108. }
  109. // no tabs after the passed in location.
  110. return -1;
  111. }
  112. /**
  113. * Indicates whether this <code>TabSet</code> is equal to another one.
  114. * @param o the <code>TabSet</code> instance which this instance
  115. * should be compared to.
  116. * @return <code>true</code> if <code>o</code> is the instance of
  117. * <code>TabSet</code>, has the same number of <code>TabStop</code>s
  118. * and they are all equal, <code>false</code> otherwise.
  119. *
  120. * @since 1.5
  121. */
  122. public boolean equals(Object o) {
  123. if (o == this) {
  124. return true;
  125. }
  126. if (o instanceof TabSet) {
  127. TabSet ts = (TabSet) o;
  128. int count = getTabCount();
  129. if (ts.getTabCount() != count) {
  130. return false;
  131. }
  132. for (int i=0; i < count; i++) {
  133. TabStop ts1 = getTab(i);
  134. TabStop ts2 = ts.getTab(i);
  135. if ((ts1 == null && ts2 != null) ||
  136. (ts1 != null && !getTab(i).equals(ts.getTab(i)))) {
  137. return false;
  138. }
  139. }
  140. return true;
  141. }
  142. return false;
  143. }
  144. /**
  145. * Returns a hashcode for this set of TabStops.
  146. * @return a hashcode value for this set of TabStops.
  147. *
  148. * @since 1.5
  149. */
  150. public int hashCode() {
  151. if (hashCode == Integer.MAX_VALUE) {
  152. hashCode = 0;
  153. int len = getTabCount();
  154. for (int i = 0; i < len; i++) {
  155. TabStop ts = getTab(i);
  156. hashCode ^= ts != null ? getTab(i).hashCode() : 0;
  157. }
  158. if (hashCode == Integer.MAX_VALUE) {
  159. hashCode -= 1;
  160. }
  161. }
  162. return hashCode;
  163. }
  164. /**
  165. * Returns the string representation of the set of tabs.
  166. */
  167. public String toString() {
  168. int tabCount = getTabCount();
  169. StringBuffer buffer = new StringBuffer("[ ");
  170. for(int counter = 0; counter < tabCount; counter++) {
  171. if(counter > 0)
  172. buffer.append(" - ");
  173. buffer.append(getTab(counter).toString());
  174. }
  175. buffer.append(" ]");
  176. return buffer.toString();
  177. }
  178. }