All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.xfa.text.TextTabList Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
package com.adobe.xfa.text;

import com.adobe.xfa.ut.UnitSpan;

import java.util.Iterator;
import java.util.SortedMap;
import java.util.TreeMap;


/**
 * Class TextTabList represents a set of tab stops (see class
 * TextTab).  Its API is designed to simplify working with the list
 * for layout operations.
 * 

*

* A tab list consists of a set of zero or more individual tab * stops, as well as an optional uniform tab stop definition. *

*

* Individual tab stops are ultimately set by the user. They may have * different types, and their offsets are chosen for visual layout, not * typically by algorithmic rule. Irrespective of the order individual * tab stops are added to a tab list, AXTE can infer a graphic order * from the tab stops' offset values, starting with the smallest and * ending with the largest. *

*

* Uniform tab stops kick in after the last individual tab, and are * offset at regular intervals, theoretically up to infinity. The * uniform tab stop definition defines that interval through its offset * and it also defines the tab type for all uniform tabs. Note that * uniform tab stops are gridded relative to the start of the line, not * the last individual tab stop. *

*

* Because the uniform tab stop definition, the application may enable * or disable it. When enabled, the tab list object effectively * presents an infinit set of tab stops, starting with the ordered * individual tab stops, and followed by an ongoing sequence of * manufactured uniform tab stops. When disabled, the last tab stop in * the list is the last individual stop. *

*

* For more information, please see the external documentation. *

* * @exclude from published api -- Mike Tardif, May 2006. */ // TODO: Check against current implementation. public class TextTabList { public final static TextTabList DEFAULT_TAB_LIST = new TextTabList(); private SortedMap moTabs; private TextTab moUniform; /** * Default constructor. *

* Construct a tab list object with an initially empty set of individual * tabs and a uniform tab definition of 0.5", left aligned. */ public TextTabList () { moUniform = TextTab.DEFAULT_TAB; } /** * Copy constructor. *

* Copy the source tab list, including the complete set of individual * tab stops and the uniform tab stop definition. * @param oSource - Source tab list to copy. */ public TextTabList (TextTabList oSource) { if (oSource.moTabs != null) { moTabs = new TreeMap(oSource.moTabs); } moUniform = oSource.moUniform; } /** * Obtain the uniform tab stop definition. * @return Current uniform tab stop definition. */ public TextTab uniform () { return noUniform() ? TextTab.DEFAULT_TAB : moUniform; } /** * Change the uniform tab stop definition. * @param oNewUniform - New uniform tab stop definition. The call is * ignored if this has a zero or negative value. */ public void uniform (TextTab oNewUniform) { if (oNewUniform.value() <= 0) { return; } moUniform = oNewUniform; } /** * Query whether the uniform tab stop definition is disabled. * @return TRUE if the uniform tab stop definition is disabled; FALSE if * enabled. */ public boolean noUniform () { return moUniform.value() == 0; } /** * Enable/disable the uniform tab stop definition. * @param bNoUniform - TRUE if the uniform tab stop definition is to be * disabled; FALSE to enable it. */ public void noUniform (boolean bNoUniform) { if (bNoUniform) { moUniform = TextTab.ZERO_TAB; } else if (moUniform.value() == 0) { moUniform = TextTab.DEFAULT_TAB; } } /** * Set a new tab stop. *

* This method adds a new tab stop to the set of individual tabs. The * new tab stop can then be retrieved in correct sequence with the * Next() and Prev() methods. Note that there may not be two tab stops * at the same offset. If the list already contains a tab stop at the * new tab's offset, the existing tab is replaced. * @param oSet - New individual tab to add to the set. */ public void set (TextTab oSet) { if (moTabs == null) { moTabs = new TreeMap(); } moTabs.put (oSet.tabStop(), oSet); } /** * Clear one tab stop. *

* If the list contains an individual tab at the offset of the parameter * passed in, remove it from the list. Otherwise, the call is ignored. * One cannot clear uniform tab stop instances. * @param oClear - Tab stop to clear. Only the offset is examined; the * type is ignored. */ public void clear (TextTab oClear) { if (moTabs != null) { moTabs.remove (oClear.tabStop()); // removes if found } } /** * Clear all tabs. *

* Remove all individual tabs and set the uniform tab stop back to its * initial definition (0.5" left). */ public void clearAll () { if (moTabs != null) { moTabs.clear(); } moUniform = TextTab.DEFAULT_TAB; } /** * Obtain the number of individual tab stops. * @return Number of individual tab stops currently in the list. Not * influenced by the state of the uniform tab stop definition. */ public int size () { return (moTabs == null) ? 0 : moTabs.size(); } /** * Obtain the next tab. *

* Given an offset measurement, this method returns the next tab from * the list. Note that a tab exactly at the given offset is not a * suitable candidate. If uniform tabs are enabled and the offset is * beyond the last individual tab stop, the appropriate uniform tab stop * is returned. If the offset is beyond the last individual tab stop * and uniform tabs are disabled, a tab with a zero offset is returned. * @param oPosition - Offset to start the search from. * @return Resulting tab stop. Note: This is currently a const * reference to static storage ans is not thread safe. Must change to * return by value as part of the HATV effort. */ public TextTab next (UnitSpan oPosition) { // First, search the tab list for a specific tab after the given // position. if (moTabs != null) { for (TextTab textTab : moTabs.values()) { if (textTab.tabStop().compareTo(oPosition) > 0) return textTab; } } // Didn't find it: are there no uniform tabs? if (noUniform()) { return TextTab.ZERO_TAB; // Compute the next uniform tab. } else { UnitSpan oValue = oPosition.grid (moUniform.tabStop()); // grid *down* always oValue = oValue.add (moUniform.tabStop()); // next grid return new TextTab (oValue, moUniform.tabType()); // construct a tab stop } } /** * Obtain the previous tab. *

* Given an offset measurement, this method returns the previous tab * from the list. Note that a tab exactly at the given offset is not a * suitable candidate. If uniform tabs are enabled and the offset is * far enough beyond the last individual tab stop, the appropriate * uniform tab stop is returned. If the offset is beyond the last * individual tab stop and uniform tabs are disabled, the last * individual tab stop is returned. * @param oPosition - Offset to start the search from. * @return Resulting tab stop. Note: This is currently a const * reference to static storage ans is not thread safe. Must change to * return by value as part of the HATV effort. */ public TextTab prev (UnitSpan oPosition) { if (oPosition.value() <= 0) { // Never try to have a tab below zero. return TextTab.ZERO_TAB; } if (moTabs == null) { return TextTab.ZERO_TAB; } // If there is a tab list, see if we are to end up before the last tab in // the list. If so, return the appropriate tab from the list. TextTab oLastTab = TextTab.ZERO_TAB; if (moTabs.size() > 0) { oLastTab = moTabs.get(moTabs.lastKey()); if (oPosition.lte (oLastTab.tabStop())) { // at/before last tab UnitSpan previous = null; for (UnitSpan currentPosition : moTabs.keySet()) { if (oPosition.compareTo(currentPosition) >= 0) { if (previous == null) return TextTab.ZERO_TAB; else return moTabs.get(previous); } previous = currentPosition; } } } if (noUniform()) { // We're beyond the last tab. If no uniform tabs, use the last one. return oLastTab; } // Otherwise, construct the appropriate uniform position and see if we // should use it. UnitSpan oUniform = oPosition.grid (moUniform.tabStop()); // grid *down* if (oUniform.equals (oPosition)) { // if wasn't changed ... oUniform = oUniform.subtract (moUniform.tabStop()); // ... force down by grid } // If there is a tab list and the appropriate uniform tab is before the // end of the list, use the last tab. if ((moTabs.size() > 0) && (oLastTab.tabStop().gte (oUniform))) { return oLastTab; } // Otherwise, tab back to the previous uniform tab. return new TextTab (oUniform, moUniform.tabType()); } /** * Assignment operator. *

* Copy the source tab list, including the complete set of individual * tab stops and the uniform tab stop definition. * @param oSource - Source tab list to copy. */ public void copyFrom (TextTabList oSource) { moUniform = oSource.moUniform; if (oSource.moTabs == null) { moTabs = null; } else { moTabs = new TreeMap(oSource.moTabs); } } /** * Equality comparison. *

* Two tab lists are considered equal if they have the same sets of tab * stops and the same uniform tab stop definition. Tab stops are * compared by both offset and type. The uniform tab stop definitions * are equal if they are both disabled or they are both enabled and * represent the same tab stop. * @param object - Tab list to compare against. * @return TRUE if the tab lists are equal; FALSE otherwise. */ public boolean equals (Object object) { if (this == object) return true; // This overrides Object.equals(boolean) directly, so... if (object == null) return false; if (object.getClass() != getClass()) return false; TextTabList compare = (TextTabList) object; if (! moUniform.equals (compare.moUniform)) return false; if (size() != compare.size()) return false; if (size() == 0) return true; // Note change from C++: sufficient to compare map values, // because map keys are derived from the values. Iterator it1 = moTabs.values().iterator(); Iterator it2 = compare.moTabs.values().iterator(); while (it1.hasNext()) { if (!it1.next().equals(it2.next())) return false; } return true; } public int hashCode() { int hash = 71; hash = (hash * 31) ^ moUniform.hashCode(); if (moTabs != null) for (TextTab textTab : moTabs.values()) hash = (hash * 31) ^ textTab.hashCode(); return hash; } /** * Inequality comparison. *

* Two tab lists are considered unequal if they have different sets of * tab stops or different uniform tab stop definitions. Tab stops are * compared by both offset and type. The uniform tab stop definitions * are unequal if their enabled/disabled states don't match or they are * both enabled and represent different tab stops. * @param oCompare - Tab list to compare against. * @return TRUE if the tab lists are not equal; FALSE otherwise. */ public boolean notEqual (TextTabList oCompare) { return ! equals (oCompare); } /** * Tab stop indexing. *

* Return one tab stop from the list, accessed by index number. This * method treats the tab list as an ordered list of individual tab stops * followed by an open-ended list of uniform tabs, if enabled. The * caller can request any tab stop from this view. * @param nIndex - Index number of desired tab stop. * @return Resulting tab stop. Note: This is currently a const * reference to static storage ans is not thread safe. Must change to * return by value as part of the HATV effort. */ public TextTab tabAt (int nIndex) { if (nIndex == 0) { return TextTab.ZERO_TAB; // "real" indexes start at 1 } int nTabs = size(); if (nIndex <= nTabs) { // within tab list ... return getTab (nIndex - 1); // ... "real" indexes start at 1 } // If we're at this point, we need to return a uniform tab (beyond the // end of the tab list). Start by determining the position of the next // uniform tab. UnitSpan oValue = null; if (nTabs > 0) { oValue = moTabs.lastKey(); } oValue = next(oValue).tabStop(); // now at next uniform tab. // Determine how many more uniform tab stops to go from oValue. int lOffset = nIndex - nTabs - 1; // Compute a new tab stop at the given offset. UnitSpan stop = moUniform.tabStop(); stop = stop.multiply(lOffset); stop = stop.add(oValue); return new TextTab (stop, moUniform.tabType()); } public void debug () { debug (0); } void debug (int indent) { String prefix = Pkg.doIndent (indent+1); System.out.println (prefix + "Tab list:"); prefix += ' '; indent += 2; if (size() > 0) { System.out.println (prefix + "Tab stops:"); for (TextTab textTab : moTabs.values()) { textTab.debug (indent); } } if (! noUniform()) { System.out.println (prefix + "Uniform:"); uniform().debug (indent); } } private final TextTab getTab (int index) { int i = 0; for (TextTab textTab : moTabs.values()) { if (i == index) return textTab; i++; } return null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy