2 * (C) Copyright IBM Corp. 1998-2004. All Rights Reserved.
\r
4 * The program is provided "as is" without any warranty express or
\r
5 * implied, including the warranty of non-infringement and the implied
\r
6 * warranties of merchantibility and fitness for a particular purpose.
\r
7 * IBM will not be liable for any damages suffered by you as a result
\r
8 * of using the Program. In no event will IBM be liable for any
\r
9 * special, indirect or consequential damages or lost profits even if
\r
10 * IBM has been advised of the possibility of their occurrence. IBM
\r
11 * will not be liable for any third party claims against you.
\r
13 package com.ibm.richtext.styledtext;
\r
15 import java.util.Vector;
\r
17 import java.io.Externalizable;
\r
18 import java.io.ObjectInput;
\r
19 import java.io.ObjectOutput;
\r
20 import java.io.IOException;
\r
23 * This class is a standard implementation of MTabRuler.
\r
24 * It can have a finite number of client-specified TabStops. After
\r
25 * the client-specified TabStops, all TabStops have type
\r
26 * <code>TabStop.kAuto</code> and are at the autospace intervals.
\r
29 public final class StandardTabRuler extends MTabRuler
\r
30 implements Externalizable
\r
32 static final String COPYRIGHT =
\r
33 "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
\r
34 private static final int CURRENT_VERSION = 1;
\r
35 private static final long serialVersionUID = 22356934;
\r
37 private static final TabStop AUTO_ZERO = new TabStop(0, TabStop.kAuto);
\r
39 private TabStop[] fTabs = null;
\r
40 private int fAutoSpacing = 36; // every 1/2 inch.
\r
43 * Create a StandardTabRuler with only auto tabs, with spacing of 36.
\r
45 public StandardTabRuler()
\r
50 * Create a StandardTabRuler with only auto tabs, with the
\r
51 * given autoSpacing.
\r
52 * @param autoSpacing the autoSpacing for this tab ruler
\r
54 public StandardTabRuler(int autoSpacing)
\r
56 fAutoSpacing = autoSpacing;
\r
60 * Create a StandardTabRuler. The first TabStops on the ruler will be
\r
61 * the TabStops in the <code>tabs</code> array. After these tabs all
\r
62 * tabs are auto tabs.
\r
63 * @param tabs an array of TabStops. The TabStops in the array must
\r
64 * be in strictly increasing order (of positions), and cannot have
\r
65 * type <code>TabStop.kAuto</code>.
\r
66 * @param autoSpacing the autoSpacing interval to use after the last
\r
67 * client-specified tab.
\r
69 public StandardTabRuler(TabStop[] tabs, int autoSpacing)
\r
71 if (tabs.length > 0) {
\r
72 validateTabArray(tabs);
\r
73 fTabs = (TabStop[]) tabs.clone();
\r
78 fAutoSpacing = autoSpacing;
\r
81 /** Tabs as provided, then autoSpacing after the last tab to eternity. Use this constructor when
\r
82 munging a ruler, it does no validation on the tabs in the vector. Vector may not be null. */
\r
84 /*public*/ StandardTabRuler(Vector v, int autoSpacing)
\r
86 fTabs = tabArrayFromVector(v);
\r
87 fAutoSpacing = autoSpacing;
\r
90 /** Construct from another ruler. No validation. Ruler may not be null. */
\r
92 /*public*/ StandardTabRuler(MTabRuler ruler)
\r
94 if (ruler == null) {
\r
95 throw new IllegalArgumentException("ruler may not be null");
\r
98 fTabs = tabArrayFromVector(vectorFromTabRuler(ruler));
\r
99 fAutoSpacing = ruler.autoSpacing();
\r
102 public void readExternal(ObjectInput in) throws IOException,
\r
103 ClassNotFoundException {
\r
105 int version = in.readInt();
\r
106 if (version != CURRENT_VERSION) {
\r
107 throw new IOException("Invalid version of StyledText: " + version);
\r
109 fTabs = (TabStop[]) in.readObject();
\r
110 fAutoSpacing = in.readInt();
\r
113 public void writeExternal(ObjectOutput out) throws IOException {
\r
115 out.writeInt(CURRENT_VERSION);
\r
116 out.writeObject(fTabs);
\r
117 out.writeInt(fAutoSpacing);
\r
121 * Return first tab in the ruler. If an autoTab, it is at position zero, and
\r
122 * all subsequent tabs will be autotabs at autoSpacing intervals.
\r
124 public TabStop firstTab()
\r
126 if (fTabs != null && fTabs.length > 0) {
\r
134 * Return the first tab in the ruler with fPosition > position. If it is an
\r
135 * autotab, it is at an increment of autoSpacing, and all subsequent tabs will be
\r
136 * autotabs at autoSpacing intervals.
\r
137 * @param position the position of the TabStop returned will be greater than this parameter
\r
139 public TabStop nextTab(int position)
\r
141 if (fTabs != null) {
\r
142 for (int i = 0; i < fTabs.length; ++i) {
\r
143 if (position < fTabs[i].getPosition())
\r
148 if (position >= 4000) { // debug: sanity check
\r
149 System.out.println("auto tab past 4000");
\r
152 return new TabStop(((position / fAutoSpacing) + 1) * fAutoSpacing, TabStop.kAuto);
\r
156 * Return the interval for autotabs.
\r
158 public int autoSpacing()
\r
160 return fAutoSpacing;
\r
164 * Compare this to another Object. Returns true if the object
\r
165 * is an MTabRuler with the same autoSpacing and tabs.
\r
167 public boolean equals(Object o)
\r
172 else if (o == null) {
\r
178 rhs = (MTabRuler)o;
\r
180 catch(ClassCastException e) {
\r
184 if (fAutoSpacing != rhs.autoSpacing())
\r
187 TabStop rhsTab = rhs.firstTab();
\r
189 if (fTabs != null) {
\r
190 for (int i = 0; i < fTabs.length; ++i) {
\r
191 if (!fTabs[i].equals(rhsTab))
\r
194 rhsTab = rhs.nextTab(rhsTab.getPosition());
\r
198 return rhsTab.getType() == TabStop.kAuto;
\r
202 * Return debug information about this tab ruler.
\r
204 public String toString()
\r
206 StringBuffer buffer = new StringBuffer(super.toString());
\r
207 buffer.append(" auto: ");
\r
208 buffer.append(Integer.toString(fAutoSpacing));
\r
210 if (fTabs != null) {
\r
211 for (int i = 0; i < fTabs.length; ++i) {
\r
212 buffer.append(fTabs[i].toString());
\r
216 return buffer.toString();
\r
219 /** Utility to convert a vector of tabs to an array. */
\r
221 private static TabStop[] tabArrayFromVector(Vector v)
\r
223 int count = v.size();
\r
224 TabStop[] tabs = new TabStop[count];
\r
225 for (int i = 0; i < count; ++i) {
\r
226 tabs[i] = (TabStop)v.elementAt(i);
\r
232 /** Utility to convert a ruler to a vector of tabs, for munging. */
\r
234 private static Vector vectorFromTabRuler(MTabRuler ruler)
\r
236 Vector v = new Vector();
\r
237 for (TabStop tab = ruler.firstTab(); tab != null && tab.getType() != TabStop.kAuto; tab = ruler.nextTab(tab.getPosition())) {
\r
244 /** Utility to validate an array of tabs. The array must not be null, must not contain null
\r
245 entries, must not be kAuto, and positions must in increasing order. */
\r
247 private static void validateTabArray(TabStop[] tabs)
\r
249 int pos = Integer.MIN_VALUE;
\r
250 for (int i = 0; i < tabs.length; ++i) {
\r
251 if (tabs[i].getType() == TabStop.kAuto) {
\r
252 throw new IllegalArgumentException("can't explicitly specify an auto tab.");
\r
254 int nextpos = tabs[i].getPosition();
\r
255 if (nextpos <= pos) {
\r
256 throw new IllegalArgumentException("tab positions must be in increasing order.");
\r
263 * Return a tab ruler identical to the given ruler, except with the
\r
265 * @param ruler the original ruler. The MTabRuler will be the same as
\r
266 * this except for the additional tab. <code>ruler</code> is not modified.
\r
267 * @param tabToAdd the tab to add to the new tab ruler
\r
268 * @return an MTabRuler resulting from this operation
\r
270 /*public*/ static MTabRuler addTabToRuler(MTabRuler ruler, TabStop tabToAdd)
\r
272 if (ruler == null || tabToAdd == null)
\r
273 throw new IllegalArgumentException("ruler and tabToAdd may not be null");
\r
275 Vector vector = new Vector();
\r
278 boolean added = false;
\r
279 for (TabStop tab = ruler.firstTab(); tab.getType() != TabStop.kAuto; tab = ruler.nextTab(pos)) {
\r
280 pos = tab.getPosition();
\r
282 if (!added && pos >= tabToAdd.getPosition()) {
\r
283 if (pos == tabToAdd.getPosition())
\r
285 vector.addElement(tabToAdd);
\r
290 vector.addElement(tab);
\r
293 vector.addElement(tabToAdd);
\r
295 return new StandardTabRuler(vector, ruler.autoSpacing());
\r
299 * Return a tab ruler identical to the given ruler, except with the
\r
300 * given tab removed.
\r
301 * @param ruler the original ruler. The MTabRuler will be the same as
\r
302 * this except for the removed tab. <code>ruler</code> is not modified.
\r
303 * @param position the position of the tab to remove from the new tab ruler
\r
304 * @return an MTabRuler resulting from this operation
\r
306 /*public*/ static MTabRuler removeTabFromRuler(MTabRuler ruler, int position)
\r
309 throw new IllegalArgumentException("ruler may not be null");
\r
311 Vector vector = new Vector();
\r
314 boolean removed = false;
\r
315 for (TabStop tab = ruler.firstTab(); tab.getType() != TabStop.kAuto; tab = ruler.nextTab(pos)) {
\r
316 pos = tab.getPosition();
\r
318 if (!removed && pos >= position) {
\r
319 if (pos == position) {
\r
321 continue; // skip this tab and continue with the remainder
\r
323 break; // we didn't remove a tab, but skipped position, so don't bother with the rest
\r
326 vector.addElement(tab);
\r
328 if (!removed) // no change
\r
331 if (vector.size() == 0)
\r
332 return new StandardTabRuler(ruler.autoSpacing());
\r
334 return new StandardTabRuler(vector, ruler.autoSpacing());
\r
338 * Return a tab ruler identical to the given ruler, except with the
\r
339 * tab at position <code>fromPosition</code> moved to position
\r
340 * <code>toPosition</code>.
\r
341 * @param ruler the original ruler. The MTabRuler will be the same as
\r
342 * this except for the moved tab. <code>ruler</code> is not modified.
\r
343 * @param fromPosition the position of the tab to move
\r
344 * @param toPosition the new position of the tab
\r
345 * @return an MTabRuler resulting from this operation
\r
347 /*public*/ static MTabRuler moveTabOnRuler(MTabRuler ruler, int fromPosition, int toPosition)
\r
350 throw new IllegalArgumentException("ruler may not be null");
\r
352 Vector vector = new Vector();
\r
355 boolean moved = false;
\r
356 for (TabStop tab = ruler.firstTab(); tab.getType() != TabStop.kAuto; tab = ruler.nextTab(pos)) {
\r
357 pos = tab.getPosition();
\r
359 if (!moved && pos == fromPosition) {
\r
361 tab = new TabStop(toPosition, tab.getType()); // copy it
\r
364 vector.addElement(tab);
\r
366 if (!moved) // no change
\r
369 return new StandardTabRuler(vector, ruler.autoSpacing());
\r