| /* |
| * @(#)$RCSfile: StandardTabRuler.java,v $ $Revision: 1.1 $ $Date: 2000/04/20 17:45:10 $ |
| * |
| * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. |
| * |
| * The program is provided "as is" without any warranty express or |
| * implied, including the warranty of non-infringement and the implied |
| * warranties of merchantibility and fitness for a particular purpose. |
| * IBM will not be liable for any damages suffered by you as a result |
| * of using the Program. In no event will IBM be liable for any |
| * special, indirect or consequential damages or lost profits even if |
| * IBM has been advised of the possibility of their occurrence. IBM |
| * will not be liable for any third party claims against you. |
| */ |
| package com.ibm.richtext.styledtext; |
| |
| import java.util.Vector; |
| |
| import java.io.Externalizable; |
| import java.io.ObjectInput; |
| import java.io.ObjectOutput; |
| import java.io.IOException; |
| |
| /** |
| * This class is a standard implementation of MTabRuler. |
| * It can have a finite number of client-specified TabStops. After |
| * the client-specified TabStops, all TabStops have type |
| * <code>TabStop.kAuto</code> and are at the autospace intervals. |
| * @see TabStop |
| */ |
| public final class StandardTabRuler extends MTabRuler |
| implements Externalizable |
| { |
| static final String COPYRIGHT = |
| "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; |
| private static final int CURRENT_VERSION = 1; |
| private static final long serialVersionUID = 22356934; |
| |
| private static final TabStop AUTO_ZERO = new TabStop(0, TabStop.kAuto); |
| |
| private TabStop[] fTabs = null; |
| private int fAutoSpacing = 36; // every 1/2 inch. |
| |
| /** |
| * Create a StandardTabRuler with only auto tabs, with spacing of 36. |
| */ |
| public StandardTabRuler() |
| { |
| } |
| |
| /** |
| * Create a StandardTabRuler with only auto tabs, with the |
| * given autoSpacing. |
| * @param autoSpacing the autoSpacing for this tab ruler |
| */ |
| public StandardTabRuler(int autoSpacing) |
| { |
| fAutoSpacing = autoSpacing; |
| } |
| |
| /** |
| * Create a StandardTabRuler. The first TabStops on the ruler will be |
| * the TabStops in the <code>tabs</code> array. After these tabs all |
| * tabs are auto tabs. |
| * @param tabs an array of TabStops. The TabStops in the array must |
| * be in strictly increasing order (of positions), and cannot have |
| * type <code>TabStop.kAuto</code>. |
| * @param autoSpacing the autoSpacing interval to use after the last |
| * client-specified tab. |
| */ |
| public StandardTabRuler(TabStop[] tabs, int autoSpacing) |
| { |
| if (tabs.length > 0) { |
| validateTabArray(tabs); |
| fTabs = (TabStop[]) tabs.clone(); |
| } |
| else { |
| fTabs = null; |
| } |
| fAutoSpacing = autoSpacing; |
| } |
| |
| /** Tabs as provided, then autoSpacing after the last tab to eternity. Use this constructor when |
| munging a ruler, it does no validation on the tabs in the vector. Vector may not be null. */ |
| |
| /*public*/ StandardTabRuler(Vector v, int autoSpacing) |
| { |
| fTabs = tabArrayFromVector(v); |
| fAutoSpacing = autoSpacing; |
| } |
| |
| /** Construct from another ruler. No validation. Ruler may not be null. */ |
| |
| /*public*/ StandardTabRuler(MTabRuler ruler) |
| { |
| if (ruler == null) { |
| throw new IllegalArgumentException("ruler may not be null"); |
| } |
| |
| fTabs = tabArrayFromVector(vectorFromTabRuler(ruler)); |
| fAutoSpacing = ruler.autoSpacing(); |
| } |
| |
| public void readExternal(ObjectInput in) throws IOException, |
| ClassNotFoundException { |
| |
| int version = in.readInt(); |
| if (version != CURRENT_VERSION) { |
| throw new IOException("Invalid version of StyledText: " + version); |
| } |
| fTabs = (TabStop[]) in.readObject(); |
| fAutoSpacing = in.readInt(); |
| } |
| |
| public void writeExternal(ObjectOutput out) throws IOException { |
| |
| out.writeInt(CURRENT_VERSION); |
| out.writeObject(fTabs); |
| out.writeInt(fAutoSpacing); |
| } |
| |
| /** |
| * Return first tab in the ruler. If an autoTab, it is at position zero, and |
| * all subsequent tabs will be autotabs at autoSpacing intervals. |
| */ |
| public TabStop firstTab() |
| { |
| if (fTabs != null && fTabs.length > 0) { |
| return fTabs[0]; |
| } |
| |
| return AUTO_ZERO; |
| } |
| |
| /** |
| * Return the first tab in the ruler with fPosition > position. If it is an |
| * autotab, it is at an increment of autoSpacing, and all subsequent tabs will be |
| * autotabs at autoSpacing intervals. |
| * @param position the position of the TabStop returned will be greater than this parameter |
| */ |
| public TabStop nextTab(int position) |
| { |
| if (fTabs != null) { |
| for (int i = 0; i < fTabs.length; ++i) { |
| if (position < fTabs[i].getPosition()) |
| return fTabs[i]; |
| } |
| } |
| |
| if (position >= 4000) { // debug: sanity check |
| System.out.println("auto tab past 4000"); |
| } |
| |
| return new TabStop(((position / fAutoSpacing) + 1) * fAutoSpacing, TabStop.kAuto); |
| } |
| |
| /** |
| * Return the interval for autotabs. |
| */ |
| public int autoSpacing() |
| { |
| return fAutoSpacing; |
| } |
| |
| /** |
| * Compare this to another Object. Returns true if the object |
| * is an MTabRuler with the same autoSpacing and tabs. |
| */ |
| public boolean equals(Object o) |
| { |
| if (o == this) { |
| return true; |
| } |
| else if (o == null) { |
| return false; |
| } |
| |
| MTabRuler rhs; |
| try { |
| rhs = (MTabRuler)o; |
| } |
| catch(ClassCastException e) { |
| return false; |
| } |
| |
| if (fAutoSpacing != rhs.autoSpacing()) |
| return false; |
| |
| TabStop rhsTab = rhs.firstTab(); |
| |
| if (fTabs != null) { |
| for (int i = 0; i < fTabs.length; ++i) { |
| if (!fTabs[i].equals(rhsTab)) |
| return false; |
| |
| rhsTab = rhs.nextTab(rhsTab.getPosition()); |
| } |
| } |
| |
| return rhsTab.getType() == TabStop.kAuto; |
| } |
| |
| /** |
| * Return debug information about this tab ruler. |
| */ |
| public String toString() |
| { |
| StringBuffer buffer = new StringBuffer(super.toString()); |
| buffer.append(" auto: "); |
| buffer.append(Integer.toString(fAutoSpacing)); |
| |
| if (fTabs != null) { |
| for (int i = 0; i < fTabs.length; ++i) { |
| buffer.append(fTabs[i].toString()); |
| } |
| } |
| |
| return buffer.toString(); |
| } |
| |
| /** Utility to convert a vector of tabs to an array. */ |
| |
| private static TabStop[] tabArrayFromVector(Vector v) |
| { |
| int count = v.size(); |
| TabStop[] tabs = new TabStop[count]; |
| for (int i = 0; i < count; ++i) { |
| tabs[i] = (TabStop)v.elementAt(i); |
| } |
| |
| return tabs; |
| } |
| |
| /** Utility to convert a ruler to a vector of tabs, for munging. */ |
| |
| private static Vector vectorFromTabRuler(MTabRuler ruler) |
| { |
| Vector v = new Vector(); |
| for (TabStop tab = ruler.firstTab(); tab != null && tab.getType() != TabStop.kAuto; tab = ruler.nextTab(tab.getPosition())) { |
| v.addElement(tab); |
| } |
| |
| return v; |
| } |
| |
| /** Utility to validate an array of tabs. The array must not be null, must not contain null |
| entries, must not be kAuto, and positions must in increasing order. */ |
| |
| private static void validateTabArray(TabStop[] tabs) |
| { |
| int pos = Integer.MIN_VALUE; |
| for (int i = 0; i < tabs.length; ++i) { |
| if (tabs[i].getType() == TabStop.kAuto) { |
| throw new IllegalArgumentException("can't explicitly specify an auto tab."); |
| } |
| int nextpos = tabs[i].getPosition(); |
| if (nextpos <= pos) { |
| throw new IllegalArgumentException("tab positions must be in increasing order."); |
| } |
| pos = nextpos; |
| } |
| } |
| |
| /** |
| * Return a tab ruler identical to the given ruler, except with the |
| * given tab added. |
| * @param ruler the original ruler. The MTabRuler will be the same as |
| * this except for the additional tab. <code>ruler</code> is not modified. |
| * @param tabToAdd the tab to add to the new tab ruler |
| * @return an MTabRuler resulting from this operation |
| */ |
| /*public*/ static MTabRuler addTabToRuler(MTabRuler ruler, TabStop tabToAdd) |
| { |
| if (ruler == null || tabToAdd == null) |
| throw new IllegalArgumentException("ruler and tabToAdd may not be null"); |
| |
| Vector vector = new Vector(); |
| |
| int pos = 0; |
| boolean added = false; |
| for (TabStop tab = ruler.firstTab(); tab.getType() != TabStop.kAuto; tab = ruler.nextTab(pos)) { |
| pos = tab.getPosition(); |
| |
| if (!added && pos >= tabToAdd.getPosition()) { |
| if (pos == tabToAdd.getPosition()) |
| tab = null; |
| vector.addElement(tabToAdd); |
| added = true; |
| } |
| |
| if (tab != null) |
| vector.addElement(tab); |
| } |
| if (!added) |
| vector.addElement(tabToAdd); |
| |
| return new StandardTabRuler(vector, ruler.autoSpacing()); |
| } |
| |
| /** |
| * Return a tab ruler identical to the given ruler, except with the |
| * given tab removed. |
| * @param ruler the original ruler. The MTabRuler will be the same as |
| * this except for the removed tab. <code>ruler</code> is not modified. |
| * @param position the position of the tab to remove from the new tab ruler |
| * @return an MTabRuler resulting from this operation |
| */ |
| /*public*/ static MTabRuler removeTabFromRuler(MTabRuler ruler, int position) |
| { |
| if (ruler == null) |
| throw new IllegalArgumentException("ruler may not be null"); |
| |
| Vector vector = new Vector(); |
| |
| int pos = 0; |
| boolean removed = false; |
| for (TabStop tab = ruler.firstTab(); tab.getType() != TabStop.kAuto; tab = ruler.nextTab(pos)) { |
| pos = tab.getPosition(); |
| |
| if (!removed && pos >= position) { |
| if (pos == position) { |
| removed = true; |
| continue; // skip this tab and continue with the remainder |
| } |
| break; // we didn't remove a tab, but skipped position, so don't bother with the rest |
| } |
| |
| vector.addElement(tab); |
| } |
| if (!removed) // no change |
| return ruler; |
| |
| if (vector.size() == 0) |
| return new StandardTabRuler(ruler.autoSpacing()); |
| |
| return new StandardTabRuler(vector, ruler.autoSpacing()); |
| } |
| |
| /** |
| * Return a tab ruler identical to the given ruler, except with the |
| * tab at position <code>fromPosition</code> moved to position |
| * <code>toPosition</code>. |
| * @param ruler the original ruler. The MTabRuler will be the same as |
| * this except for the moved tab. <code>ruler</code> is not modified. |
| * @param fromPosition the position of the tab to move |
| * @param toPosition the new position of the tab |
| * @return an MTabRuler resulting from this operation |
| */ |
| /*public*/ static MTabRuler moveTabOnRuler(MTabRuler ruler, int fromPosition, int toPosition) |
| { |
| if (ruler == null) |
| throw new IllegalArgumentException("ruler may not be null"); |
| |
| Vector vector = new Vector(); |
| |
| int pos = 0; |
| boolean moved = false; |
| for (TabStop tab = ruler.firstTab(); tab.getType() != TabStop.kAuto; tab = ruler.nextTab(pos)) { |
| pos = tab.getPosition(); |
| |
| if (!moved && pos == fromPosition) { |
| moved = true; |
| tab = new TabStop(toPosition, tab.getType()); // copy it |
| } |
| |
| vector.addElement(tab); |
| } |
| if (!moved) // no change |
| return ruler; |
| |
| return new StandardTabRuler(vector, ruler.autoSpacing()); |
| } |
| |
| } |