]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_2_1-src/src/com/ibm/richtext/styledtext/StandardTabRuler.java
go
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / richtext / styledtext / StandardTabRuler.java
1 /*\r
2  * (C) Copyright IBM Corp. 1998-2004.  All Rights Reserved.\r
3  *\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
12  */\r
13 package com.ibm.richtext.styledtext;\r
14 \r
15 import java.util.Vector;\r
16 \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
21 \r
22 /**\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
27  * @see TabStop\r
28  */\r
29 public final class StandardTabRuler extends MTabRuler\r
30                                     implements Externalizable\r
31 {\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
36 \r
37     private static final TabStop AUTO_ZERO = new TabStop(0, TabStop.kAuto);\r
38 \r
39     private TabStop[] fTabs = null;\r
40     private int fAutoSpacing = 36; // every 1/2 inch.\r
41 \r
42     /**\r
43      * Create a StandardTabRuler with only auto tabs, with spacing of 36.\r
44      */\r
45     public StandardTabRuler()\r
46     {\r
47     }\r
48 \r
49     /**\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
53      */\r
54     public StandardTabRuler(int autoSpacing)\r
55     {\r
56         fAutoSpacing = autoSpacing;\r
57     }\r
58 \r
59     /**\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
68      */\r
69     public StandardTabRuler(TabStop[] tabs, int autoSpacing)\r
70     {\r
71         if (tabs.length > 0) {\r
72             validateTabArray(tabs);\r
73             fTabs = (TabStop[]) tabs.clone();\r
74         }\r
75         else {\r
76             fTabs = null;\r
77         }\r
78         fAutoSpacing = autoSpacing;\r
79     }\r
80 \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
83 \r
84     /*public*/ StandardTabRuler(Vector v, int autoSpacing)\r
85     {\r
86         fTabs = tabArrayFromVector(v);\r
87         fAutoSpacing = autoSpacing;\r
88     }\r
89 \r
90     /** Construct from another ruler. No validation. Ruler may not be null. */\r
91 \r
92     /*public*/ StandardTabRuler(MTabRuler ruler)\r
93     {\r
94         if (ruler == null) {\r
95             throw new IllegalArgumentException("ruler may not be null");\r
96         }\r
97 \r
98         fTabs = tabArrayFromVector(vectorFromTabRuler(ruler));\r
99         fAutoSpacing = ruler.autoSpacing();\r
100     }\r
101 \r
102     public void readExternal(ObjectInput in) throws IOException,\r
103                                             ClassNotFoundException {\r
104 \r
105         int version = in.readInt();\r
106         if (version != CURRENT_VERSION) {\r
107             throw new IOException("Invalid version of StyledText: " + version);\r
108         }\r
109         fTabs = (TabStop[]) in.readObject();\r
110         fAutoSpacing = in.readInt();\r
111     }\r
112 \r
113     public void writeExternal(ObjectOutput out) throws IOException {\r
114 \r
115         out.writeInt(CURRENT_VERSION);\r
116         out.writeObject(fTabs);\r
117         out.writeInt(fAutoSpacing);\r
118     }\r
119 \r
120     /**\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
123      */\r
124     public TabStop firstTab()\r
125     {\r
126         if (fTabs != null && fTabs.length > 0) {\r
127             return fTabs[0];\r
128         }\r
129 \r
130         return AUTO_ZERO;\r
131     }\r
132 \r
133     /**\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
138      */\r
139     public TabStop nextTab(int position)\r
140     {\r
141         if (fTabs != null) {\r
142             for (int i = 0; i < fTabs.length; ++i) {\r
143                 if (position < fTabs[i].getPosition())\r
144                     return fTabs[i];\r
145             }\r
146         }\r
147 \r
148         if (position >= 4000) { // debug: sanity check\r
149             System.out.println("auto tab past 4000");\r
150         }\r
151 \r
152         return new TabStop(((position / fAutoSpacing) + 1) * fAutoSpacing, TabStop.kAuto);\r
153     }\r
154 \r
155     /**\r
156      * Return the interval for autotabs.\r
157      */\r
158     public int autoSpacing()\r
159     {\r
160         return fAutoSpacing;\r
161     }\r
162 \r
163     /**\r
164      * Compare this to another Object. Returns true if the object\r
165      * is an MTabRuler with the same autoSpacing and tabs.\r
166      */\r
167     public boolean equals(Object o)\r
168     {\r
169         if (o == this) {\r
170             return true;\r
171         }\r
172         else if (o == null) {\r
173             return false;\r
174         }\r
175         \r
176         MTabRuler rhs;\r
177         try {\r
178             rhs = (MTabRuler)o;\r
179         }\r
180         catch(ClassCastException e) {\r
181             return false;\r
182         }\r
183 \r
184         if (fAutoSpacing != rhs.autoSpacing())\r
185             return false;\r
186 \r
187         TabStop rhsTab = rhs.firstTab();\r
188 \r
189         if (fTabs != null) {\r
190             for (int i = 0; i < fTabs.length; ++i) {\r
191                 if (!fTabs[i].equals(rhsTab))\r
192                     return false;\r
193 \r
194                 rhsTab = rhs.nextTab(rhsTab.getPosition());\r
195             }\r
196         }\r
197 \r
198         return rhsTab.getType() == TabStop.kAuto;\r
199     }\r
200 \r
201     /**\r
202      * Return debug information about this tab ruler.\r
203      */\r
204     public String toString()\r
205     {\r
206         StringBuffer buffer = new StringBuffer(super.toString());\r
207         buffer.append(" auto: ");\r
208         buffer.append(Integer.toString(fAutoSpacing));\r
209 \r
210         if (fTabs != null) {\r
211             for (int i = 0; i < fTabs.length; ++i) {\r
212                 buffer.append(fTabs[i].toString());\r
213             }\r
214         }\r
215 \r
216         return buffer.toString();\r
217     }\r
218 \r
219     /** Utility to convert a vector of tabs to an array. */\r
220 \r
221     private static TabStop[] tabArrayFromVector(Vector v)\r
222     {\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
227         }\r
228 \r
229         return tabs;\r
230     }\r
231 \r
232     /** Utility to convert a ruler to a vector of tabs, for munging. */\r
233 \r
234     private static Vector vectorFromTabRuler(MTabRuler ruler)\r
235     {\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
238             v.addElement(tab);\r
239         }\r
240 \r
241         return v;\r
242     }\r
243 \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
246 \r
247     private static void validateTabArray(TabStop[] tabs)\r
248     {\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
253             }\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
257             }\r
258             pos = nextpos;\r
259         }\r
260     }\r
261 \r
262     /**\r
263      * Return a tab ruler identical to the given ruler, except with the\r
264      * given tab added.\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
269      */\r
270     /*public*/ static MTabRuler addTabToRuler(MTabRuler ruler, TabStop tabToAdd)\r
271     {\r
272         if (ruler == null || tabToAdd == null)\r
273             throw new IllegalArgumentException("ruler and tabToAdd may not be null");\r
274 \r
275         Vector vector = new Vector();\r
276 \r
277         int pos = 0;\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
281 \r
282             if (!added && pos >= tabToAdd.getPosition()) {\r
283                 if (pos == tabToAdd.getPosition())\r
284                     tab = null;\r
285                 vector.addElement(tabToAdd);\r
286                 added = true;\r
287             }\r
288 \r
289             if (tab != null)\r
290                 vector.addElement(tab);\r
291         }\r
292         if (!added)\r
293             vector.addElement(tabToAdd);\r
294 \r
295         return new StandardTabRuler(vector, ruler.autoSpacing());\r
296     }\r
297 \r
298     /**\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
305      */\r
306     /*public*/ static MTabRuler removeTabFromRuler(MTabRuler ruler, int position)\r
307     {\r
308         if (ruler == null)\r
309             throw new IllegalArgumentException("ruler may not be null");\r
310 \r
311         Vector vector = new Vector();\r
312 \r
313         int pos = 0;\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
317 \r
318             if (!removed && pos >= position) {\r
319                 if (pos == position) {\r
320                     removed = true;\r
321                     continue; // skip this tab and continue with the remainder\r
322                 }\r
323                 break; // we didn't remove a tab, but skipped position, so don't bother with the rest\r
324             }\r
325 \r
326             vector.addElement(tab);\r
327         }\r
328         if (!removed) // no change\r
329             return ruler;\r
330 \r
331         if (vector.size() == 0)\r
332             return new StandardTabRuler(ruler.autoSpacing());\r
333 \r
334         return new StandardTabRuler(vector, ruler.autoSpacing());\r
335     }\r
336 \r
337     /**\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
346      */\r
347     /*public*/ static MTabRuler moveTabOnRuler(MTabRuler ruler, int fromPosition, int toPosition)\r
348     {\r
349         if (ruler == null)\r
350             throw new IllegalArgumentException("ruler may not be null");\r
351 \r
352         Vector vector = new Vector();\r
353 \r
354         int pos = 0;\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
358 \r
359             if (!moved && pos == fromPosition) {\r
360                 moved = true;\r
361                 tab = new TabStop(toPosition, tab.getType()); // copy it\r
362             }\r
363 \r
364             vector.addElement(tab);\r
365         }\r
366         if (!moved) // no change\r
367             return ruler;\r
368 \r
369         return new StandardTabRuler(vector, ruler.autoSpacing());\r
370     }\r
371 \r
372 }\r