You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ge...@apache.org on 2005/12/01 07:04:00 UTC
svn commit: r350181 [135/198] - in
/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core: ./ depends/
depends/files/ depends/jars/ depends/libs/ depends/libs/linux.IA32/
depends/libs/win.IA32/ depends/oss/ depends/oss/linux.IA32/
depends/oss/win....
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/AttributedString.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/AttributedString.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/AttributedString.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/AttributedString.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,590 @@
+/* Copyright 1998, 2005 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.text;
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+
+import com.ibm.oti.util.Msg;
+
+/**
+ * AttributedString
+ */
+public class AttributedString {
+
+ String text;
+
+ Map attributeMap;
+
+ static class Range {
+ int start, end;
+
+ Object value;
+
+ Range(int s, int e, Object v) {
+ start = s;
+ end = e;
+ value = v;
+ }
+ }
+
+ static class AttributedIterator implements AttributedCharacterIterator {
+
+ private int begin, end, offset;
+
+ private AttributedString attrString;
+
+ private HashSet attributesAllowed;
+
+ AttributedIterator(AttributedString attrString) {
+ this.attrString = attrString;
+ begin = 0;
+ end = attrString.text.length();
+ offset = 0;
+ }
+
+ AttributedIterator(AttributedString attrString,
+ AttributedCharacterIterator.Attribute[] attributes, int begin,
+ int end) {
+ if (begin < 0 || end > attrString.text.length() || begin > end)
+ throw new IllegalArgumentException();
+ this.begin = begin;
+ this.end = end;
+ offset = begin;
+ this.attrString = attrString;
+ if (attributes != null) {
+ HashSet set = new HashSet((attributes.length * 4 / 3) + 1);
+ for (int i = attributes.length; --i >= 0;)
+ set.add(attributes[i]);
+ attributesAllowed = set;
+ }
+ }
+
+ /**
+ * Answers a new StringCharacterIterator with the same source String,
+ * begin, end, and current index as this StringCharacterIterator.
+ *
+ * @return a shallow copy of this StringCharacterIterator
+ *
+ * @see java.lang.Cloneable
+ */
+ public Object clone() {
+ try {
+ AttributedIterator clone = (AttributedIterator) super.clone();
+ if (attributesAllowed != null)
+ clone.attributesAllowed = (HashSet) attributesAllowed
+ .clone();
+ return clone;
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Answers the character at the current index in the source String.
+ *
+ * @return the current character, or DONE if the current index is past
+ * the end
+ */
+ public char current() {
+ if (offset == end)
+ return DONE;
+ return attrString.text.charAt(offset);
+ }
+
+ /**
+ * Sets the current position to the begin index and answers the
+ * character at the begin index.
+ *
+ * @return the character at the begin index
+ */
+ public char first() {
+ if (begin == end)
+ return DONE;
+ offset = begin;
+ return attrString.text.charAt(offset);
+ }
+
+ /**
+ * Answers the begin index in the source String.
+ *
+ * @return the index of the first character to iterate
+ */
+ public int getBeginIndex() {
+ return begin;
+ }
+
+ /**
+ * Answers the end index in the source String.
+ *
+ * @return the index one past the last character to iterate
+ */
+ public int getEndIndex() {
+ return end;
+ }
+
+ /**
+ * Answers the current index in the source String.
+ *
+ * @return the current index
+ */
+ public int getIndex() {
+ return offset;
+ }
+
+ private boolean inRange(Range range) {
+ if (!(range.value instanceof Annotation))
+ return true;
+ return range.start >= begin && range.start < end
+ && range.end > begin && range.end <= end;
+ }
+
+ private boolean inRange(ArrayList ranges) {
+ Iterator it = ranges.iterator();
+ while (it.hasNext()) {
+ Range range = (Range) it.next();
+ if (range.start >= begin && range.start < end) {
+ return !(range.value instanceof Annotation)
+ || (range.end > begin && range.end <= end);
+ } else if (range.end > begin && range.end <= end) {
+ return !(range.value instanceof Annotation)
+ || (range.start >= begin && range.start < end);
+ }
+ }
+ return false;
+ }
+
+ public Set getAllAttributeKeys() {
+ if (begin == 0 && end == attrString.text.length()
+ && attributesAllowed == null)
+ return attrString.attributeMap.keySet();
+
+ HashSet result = new HashSet(
+ (attrString.attributeMap.size() * 4 / 3) + 1);
+ Iterator it = attrString.attributeMap.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry entry = (Map.Entry) it.next();
+ if (attributesAllowed == null
+ || attributesAllowed.contains(entry.getKey())) {
+ ArrayList ranges = (ArrayList) entry.getValue();
+ if (inRange(ranges))
+ result.add(entry.getKey());
+ }
+ }
+ return result;
+ }
+
+ private Object currentValue(ArrayList ranges) {
+ Iterator it = ranges.iterator();
+ while (it.hasNext()) {
+ Range range = (Range) it.next();
+ if (offset >= range.start && offset < range.end)
+ return inRange(range) ? range.value : null;
+ }
+ return null;
+ }
+
+ public Object getAttribute(
+ AttributedCharacterIterator.Attribute attribute) {
+ if (attributesAllowed != null
+ && !attributesAllowed.contains(attribute))
+ return null;
+ ArrayList ranges = (ArrayList) attrString.attributeMap
+ .get(attribute);
+ if (ranges == null)
+ return null;
+ return currentValue(ranges);
+ }
+
+ public Map getAttributes() {
+ HashMap result = new HashMap(
+ (attrString.attributeMap.size() * 4 / 3) + 1);
+ Iterator it = attrString.attributeMap.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry entry = (Map.Entry) it.next();
+ if (attributesAllowed == null
+ || attributesAllowed.contains(entry.getKey())) {
+ Object value = currentValue((ArrayList) entry.getValue());
+ if (value != null)
+ result.put(entry.getKey(), value);
+ }
+ }
+ return result;
+ }
+
+ public int getRunLimit() {
+ return getRunLimit(getAllAttributeKeys());
+ }
+
+ private int runLimit(ArrayList ranges) {
+ int result = end;
+ ListIterator it = ranges.listIterator(ranges.size());
+ while (it.hasPrevious()) {
+ Range range = (Range) it.previous();
+ if (range.end <= begin)
+ break;
+ if (offset >= range.start && offset < range.end) {
+ return inRange(range) ? range.end : result;
+ } else if (offset >= range.end)
+ break;
+ result = range.start;
+ }
+ return result;
+ }
+
+ public int getRunLimit(AttributedCharacterIterator.Attribute attribute) {
+ if (attributesAllowed != null
+ && !attributesAllowed.contains(attribute))
+ return end;
+ ArrayList ranges = (ArrayList) attrString.attributeMap
+ .get(attribute);
+ if (ranges == null)
+ return end;
+ return runLimit(ranges);
+ }
+
+ public int getRunLimit(Set attributes) {
+ int limit = end;
+ Iterator it = attributes.iterator();
+ while (it.hasNext()) {
+ AttributedCharacterIterator.Attribute attribute = (AttributedCharacterIterator.Attribute) it
+ .next();
+ int newLimit = getRunLimit(attribute);
+ if (newLimit < limit)
+ limit = newLimit;
+ }
+ return limit;
+ }
+
+ public int getRunStart() {
+ return getRunStart(getAllAttributeKeys());
+ }
+
+ private int runStart(ArrayList ranges) {
+ int result = begin;
+ Iterator it = ranges.iterator();
+ while (it.hasNext()) {
+ Range range = (Range) it.next();
+ if (range.start >= end)
+ break;
+ if (offset >= range.start && offset < range.end) {
+ return inRange(range) ? range.start : result;
+ } else if (offset < range.start)
+ break;
+ result = range.end;
+ }
+ return result;
+ }
+
+ public int getRunStart(AttributedCharacterIterator.Attribute attribute) {
+ if (attributesAllowed != null
+ && !attributesAllowed.contains(attribute))
+ return begin;
+ ArrayList ranges = (ArrayList) attrString.attributeMap
+ .get(attribute);
+ if (ranges == null)
+ return begin;
+ return runStart(ranges);
+ }
+
+ public int getRunStart(Set attributes) {
+ int start = begin;
+ Iterator it = attributes.iterator();
+ while (it.hasNext()) {
+ AttributedCharacterIterator.Attribute attribute = (AttributedCharacterIterator.Attribute) it
+ .next();
+ int newStart = getRunStart(attribute);
+ if (newStart > start)
+ start = newStart;
+ }
+ return start;
+ }
+
+ /**
+ * Sets the current position to the end index - 1 and answers the
+ * character at the current position.
+ *
+ * @return the character before the end index
+ */
+ public char last() {
+ if (begin == end)
+ return DONE;
+ offset = end - 1;
+ return attrString.text.charAt(offset);
+ }
+
+ /**
+ * Increments the current index and returns the character at the new
+ * index.
+ *
+ * @return the character at the next index, or DONE if the next index is
+ * past the end
+ */
+ public char next() {
+ if (offset >= (end - 1)) {
+ offset = end;
+ return DONE;
+ }
+ return attrString.text.charAt(++offset);
+ }
+
+ /**
+ * Decrements the current index and returns the character at the new
+ * index.
+ *
+ * @return the character at the previous index, or DONE if the previous
+ * index is past the beginning
+ */
+ public char previous() {
+ if (offset == begin)
+ return DONE;
+ return attrString.text.charAt(--offset);
+ }
+
+ /**
+ * Sets the current index in the source String.
+ *
+ * @return the character at the new index, or DONE if the index is past
+ * the end
+ *
+ * @exception IllegalArgumentException
+ * when the new index is less than the begin index or
+ * greater than the end index
+ */
+ public char setIndex(int location) {
+ if (location < begin || location > end)
+ throw new IllegalArgumentException();
+ offset = location;
+ if (offset == end)
+ return DONE;
+ return attrString.text.charAt(offset);
+ }
+ }
+
+ public AttributedString(AttributedCharacterIterator iterator) {
+ StringBuffer buffer = new StringBuffer();
+ while (iterator.current() != CharacterIterator.DONE) {
+ buffer.append(iterator.current());
+ iterator.next();
+ }
+ text = buffer.toString();
+ Set attributes = iterator.getAllAttributeKeys();
+ attributeMap = new HashMap((attributes.size() * 4 / 3) + 1);
+
+ Iterator it = attributes.iterator();
+ while (it.hasNext()) {
+ AttributedCharacterIterator.Attribute attribute = (AttributedCharacterIterator.Attribute) it
+ .next();
+ iterator.setIndex(0);
+ while (iterator.current() != CharacterIterator.DONE) {
+ int start = iterator.getRunStart(attribute);
+ int limit = iterator.getRunLimit(attribute);
+ Object value = iterator.getAttribute(attribute);
+ if (value != null)
+ addAttribute(attribute, value, start, limit);
+ iterator.setIndex(limit);
+ }
+ }
+ }
+
+ private AttributedString(AttributedCharacterIterator iterator, int start,
+ int end, Set attributes) {
+ if (start < iterator.getBeginIndex() || end > iterator.getEndIndex()
+ || start > end)
+ throw new IllegalArgumentException();
+
+ StringBuffer buffer = new StringBuffer();
+ iterator.setIndex(start);
+ while (iterator.getIndex() < end) {
+ buffer.append(iterator.current());
+ iterator.next();
+ }
+ text = buffer.toString();
+ attributeMap = new HashMap((attributes.size() * 4 / 3) + 1);
+
+ Iterator it = attributes.iterator();
+ while (it.hasNext()) {
+ AttributedCharacterIterator.Attribute attribute = (AttributedCharacterIterator.Attribute) it
+ .next();
+ iterator.setIndex(start);
+ while (iterator.getIndex() < end) {
+ Object value = iterator.getAttribute(attribute);
+ int runStart = iterator.getRunStart(attribute);
+ int limit = iterator.getRunLimit(attribute);
+ if ((value instanceof Annotation && runStart >= start && limit <= end)
+ || (value != null && !(value instanceof Annotation))) {
+ addAttribute(attribute, value, (runStart < start ? start
+ : runStart)
+ - start, (limit > end ? end : limit) - start);
+ }
+ iterator.setIndex(limit);
+ }
+ }
+ }
+
+ public AttributedString(AttributedCharacterIterator iterator, int start,
+ int end) {
+ this(iterator, start, end, iterator.getAllAttributeKeys());
+ }
+
+ public AttributedString(AttributedCharacterIterator iterator, int start,
+ int end, AttributedCharacterIterator.Attribute[] attributes) {
+ this(iterator, start, end, new HashSet(Arrays.asList(attributes)));
+ }
+
+ public AttributedString(String value) {
+ if (value == null)
+ throw new NullPointerException();
+ text = value;
+ attributeMap = new HashMap(11);
+ }
+
+ public AttributedString(String value, Map attributes) {
+ if (value == null)
+ throw new NullPointerException();
+ if (value.length() == 0 && !attributes.isEmpty())
+ throw new IllegalArgumentException(Msg.getString("K000e"));
+ text = value;
+ attributeMap = new HashMap((attributes.size() * 4 / 3) + 1);
+ Iterator it = attributes.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry entry = (Map.Entry) it.next();
+ ArrayList ranges = new ArrayList(1);
+ ranges.add(new Range(0, text.length(), entry.getValue()));
+ attributeMap.put(entry.getKey(), ranges);
+ }
+ }
+
+ public void addAttribute(AttributedCharacterIterator.Attribute attribute,
+ Object value) {
+ if (text.length() == 0)
+ throw new IllegalArgumentException();
+
+ ArrayList ranges = (ArrayList) attributeMap.get(attribute);
+ if (ranges == null) {
+ ranges = new ArrayList(1);
+ attributeMap.put(attribute, ranges);
+ } else {
+ ranges.clear();
+ }
+ ranges.add(new Range(0, text.length(), value));
+ }
+
+ public void addAttribute(AttributedCharacterIterator.Attribute attribute,
+ Object value, int start, int end) {
+ if (start < 0 || end > text.length() || start >= end)
+ throw new IllegalArgumentException();
+
+ ArrayList ranges = (ArrayList) attributeMap.get(attribute);
+ if (ranges == null) {
+ ranges = new ArrayList(1);
+ ranges.add(new Range(start, end, value));
+ attributeMap.put(attribute, ranges);
+ return;
+ }
+ ListIterator it = ranges.listIterator();
+ while (it.hasNext()) {
+ Range range = (Range) it.next();
+ if (end <= range.start) {
+ it.previous();
+ break;
+ } else if (start < range.end
+ || (start == range.end && (value == null ? range.value == null
+ : value.equals(range.value)))) {
+ Range r1 = null, r3;
+ it.remove();
+ r1 = new Range(range.start, start, range.value);
+ r3 = new Range(end, range.end, range.value);
+
+ while (end > range.end && it.hasNext()) {
+ range = (Range) it.next();
+ if (end <= range.end) {
+ if (end > range.start
+ || (end == range.start && (value == null ? range.value == null
+ : value.equals(range.value)))) {
+ it.remove();
+ r3 = new Range(end, range.end, range.value);
+ break;
+ }
+ } else
+ it.remove();
+ }
+
+ if (value == null ? r1.value == null : value.equals(r1.value)) {
+ if (value == null ? r3.value == null : value
+ .equals(r3.value)) {
+ it.add(new Range(r1.start < start ? r1.start : start,
+ r3.end > end ? r3.end : end, r1.value));
+ } else {
+ it.add(new Range(r1.start < start ? r1.start : start,
+ end, r1.value));
+ if (r3.start < r3.end)
+ it.add(r3);
+ }
+ } else {
+ if (value == null ? r3.value == null : value
+ .equals(r3.value)) {
+ if (r1.start < r1.end)
+ it.add(r1);
+ it.add(new Range(start, r3.end > end ? r3.end : end,
+ r3.value));
+ } else {
+ if (r1.start < r1.end)
+ it.add(r1);
+ it.add(new Range(start, end, value));
+ if (r3.start < r3.end)
+ it.add(r3);
+ }
+ }
+ return;
+ }
+ }
+ it.add(new Range(start, end, value));
+ }
+
+ public void addAttributes(Map attributes, int start, int end) {
+ Iterator it = attributes.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry entry = (Map.Entry) it.next();
+ addAttribute(
+ (AttributedCharacterIterator.Attribute) entry.getKey(),
+ entry.getValue(), start, end);
+ }
+ }
+
+ public AttributedCharacterIterator getIterator() {
+ return new AttributedIterator(this);
+ }
+
+ public AttributedCharacterIterator getIterator(
+ AttributedCharacterIterator.Attribute[] attributes) {
+ return new AttributedIterator(this, attributes, 0, text.length());
+ }
+
+ public AttributedCharacterIterator getIterator(
+ AttributedCharacterIterator.Attribute[] attributes, int start,
+ int end) {
+ return new AttributedIterator(this, attributes, start, end);
+ }
+
+}
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/Bidi.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/Bidi.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/Bidi.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/Bidi.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,463 @@
+/* Copyright 2005 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.text;
+
+
+import java.util.Arrays;
+import java.util.LinkedList;
+
+import com.ibm.text.BidiRun;
+import com.ibm.text.BidiWrapper;
+
+/**
+ * Bidi is the class providing the bidirectional algorithm. The algorithm is
+ * defined in the Unicode Standard Annex #9, version 13, also described in The
+ * Unicode Standard, Version 4.0 .
+ *
+ * Use a Bidi object to get the infomation on the position reordering of a
+ * bidirectional text, such as Arabic or Hebrew. The natural display ordering of
+ * horizontal text in these languages is from right to left, while they order
+ * numbers from left to right.
+ *
+ * If the text contains multiple runs, the information of each run can be
+ * obtained from the run index. The level of any particular run indicates the
+ * direction of the text as well as the nesting level. Left-to-right runs have
+ * even levels while right-to-left runs have odd levels.
+ *
+ */
+public final class Bidi {
+ /**
+ * Constant that indicates the default base level. If there is no strong
+ * character, then set the paragraph level to 0 (left-to-right).
+ */
+ public static final int DIRECTION_DEFAULT_LEFT_TO_RIGHT = -2;
+
+ /**
+ * Constant that indicates the default base level. If there is no strong
+ * character, then set the paragraph level to 1 (right-to-left).
+ */
+ public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = -1;
+
+ /**
+ * Constant that specifies the default base level as 0 (left-to-right).
+ */
+ public static final int DIRECTION_LEFT_TO_RIGHT = 0;
+
+ /**
+ * Constant that specifies the default base level as 1 (right-to-left).
+ */
+ public static final int DIRECTION_RIGHT_TO_LEFT = 1;
+
+ /**
+ * Create a Bidi object from the AttributedCharacterIterator of a paragraph
+ * text.
+ *
+ * The RUN_DIRECTION attribute determines the base direction of the
+ * bidirectional text. If it's not specified explicitly, the algorithm uses
+ * DIRECTION_DEFAULT_LEFT_TO_RIGHT by default.
+ *
+ * The BIDI_EMBEDDING attribute specifies the level of embedding for each
+ * character. Values between -1 and -62 denote overrides at the level's
+ * absolute value, values from 1 to 62 indicate embeddings, and the
+ * 0 value indicates the level is calculated by the algorithm automatically.
+ * For the character with no BIDI_EMBEDDING attribute or with a improper
+ * attribute value, such as a null value, the algorithm treats its embedding
+ * level as 0.
+ *
+ * The NUMERIC_SHAPING attribute specifies the instance of NumericShaper
+ * used to convert European digits to other decimal digits before performing
+ * the bidi algorithm.
+ *
+ * @param paragraph
+ *
+ * @see TextAttribute.BIDI_EMBEDDING
+ * @see TextAttribute.NUMERIC_SHAPING
+ * @see TextAttribute.RUN_DIRECTION
+ */
+ public Bidi(AttributedCharacterIterator paragraph) {
+ /*
+ * TODO: dependency on java.awt.font.TextAttribute and
+ * java.awt.font.NumericShaper which is not implemented yet.
+ */
+ }
+
+ /**
+ * Create a Bidi object.
+ *
+ * @param text
+ * the char array of the paragraph text.
+ * @param textStart
+ * the start offset of the text array to perform the algorithm.
+ * @param embeddings
+ * the embedding level array of the paragraph text, specifying
+ * the embedding level infomation for each character. Values
+ * between -1 and -62 denote overrides at the level's absolute
+ * value, values from 1 to 62 indicate embeddings, and the 0
+ * value indicates the level is calculated by the algorithm
+ * automatically.
+ * @param embStart
+ * the start offset of the embeddings array to perform the
+ * algorithm.
+ * @param paragraphLength
+ * the length of the text to perform the algorithm. It must be
+ * text.length >= textStart + paragraphLength, and
+ * embeddings.length >= embStart + paragraphLength.
+ * @param flags
+ * indicates the base direction of the bidirectional text. It is
+ * expected that this will be one of the direction constant
+ * values defined in this class. An unknown value is treated as
+ * DIRECTION_DEFAULT_LEFT_TO_RIGHT.
+ *
+ * @see #DIRECTION_LEFT_TO_RIGHT
+ * @see #DIRECTION_RIGHT_TO_LEFT
+ * @see #DIRECTION_DEFAULT_RIGHT_TO_LEFT
+ * @see #DIRECTION_DEFAULT_LEFT_TO_RIGHT
+ */
+ public Bidi(char[] text, int textStart, byte[] embeddings, int embStart,
+ int paragraphLength, int flags) {
+ long pBidi = createUBiDi(text, textStart, embeddings, embStart,
+ paragraphLength, flags);
+ readBidiInfo(pBidi);
+ BidiWrapper.ubidi_close(pBidi);
+ }
+
+ /**
+ * Create a Bidi object.
+ *
+ * @param paragraph
+ * the String containing the paragraph text to perform the
+ * algorithm.
+ * @param flags
+ * indicates the base direction of the bidirectional text. It is
+ * expected that this will be one of the direction constant
+ * values defined in this class. An unknown value is treated as
+ * DIRECTION_DEFAULT_LEFT_TO_RIGHT.
+ *
+ * @see #DIRECTION_LEFT_TO_RIGHT
+ * @see #DIRECTION_RIGHT_TO_LEFT
+ * @see #DIRECTION_DEFAULT_RIGHT_TO_LEFT
+ * @see #DIRECTION_DEFAULT_LEFT_TO_RIGHT
+ */
+ public Bidi(String paragraph, int flags) {
+ this((paragraph == null ? null : paragraph.toCharArray()), 0, null, 0,
+ (paragraph == null ? 0 : paragraph.length()), flags);
+ }
+
+ // create the native UBiDi struct, need to be closed with ubidi_close().
+ private static long createUBiDi(char[] text, int textStart,
+ byte[] embeddings, int embStart, int paragraphLength, int flags) {
+ char[] realText = null;
+
+ byte[] realEmbeddings = null;
+
+ if (text == null || text.length < textStart + paragraphLength) {
+ throw new IllegalArgumentException();
+ }
+ realText = new char[paragraphLength];
+ System.arraycopy(text, textStart, realText, 0, paragraphLength);
+
+ if (embeddings != null) {
+ if (embeddings.length < embStart + paragraphLength) {
+ throw new IllegalArgumentException();
+ }
+ Bidi temp = new Bidi(text, textStart, null, 0, paragraphLength,
+ flags);
+ realEmbeddings = new byte[paragraphLength];
+ System.arraycopy(temp.offsetLevel, 0, realEmbeddings, 0,
+ paragraphLength);
+ for (int i = 0; i < paragraphLength; i++) {
+ byte e = embeddings[i];
+ if (e < 0) {
+ realEmbeddings[i] = (byte) (BidiWrapper.UBIDI_LEVEL_OVERRIDE - e);
+ } else if (e > 0) {
+ realEmbeddings[i] = e;
+ } else {
+ realEmbeddings[i] |= (byte) BidiWrapper.UBIDI_LEVEL_OVERRIDE;
+ }
+ }
+ }
+
+ if (flags > 1 || flags < -2) {
+ flags = 0;
+ }
+
+ long bidi = BidiWrapper.ubidi_open();
+ BidiWrapper.ubidi_setPara(bidi, realText, paragraphLength,
+ (byte) flags, realEmbeddings);
+ return bidi;
+ }
+
+ // private constructor, used by createLineBidi()
+ private Bidi(long pBidi) {
+ readBidiInfo(pBidi);
+ }
+
+ // read info from the native UBiDi struct
+ private void readBidiInfo(long pBidi) {
+
+ length = BidiWrapper.ubidi_getLength(pBidi);
+
+ offsetLevel = (length == 0) ? null : BidiWrapper.ubidi_getLevels(pBidi);
+
+ baseLevel = BidiWrapper.ubidi_getParaLevel(pBidi);
+
+ int runCount = BidiWrapper.ubidi_countRuns(pBidi);
+ if (runCount == 0) {
+ runCount = 1;
+ runs = new BidiRun[runCount];
+ runs[0] = new BidiRun(0, 0, baseLevel);
+ } else if (runCount < 0) {
+ runCount = 0;
+ runs = null;
+ } else {
+ runs = new BidiRun[runCount];
+ for (int i = 0; i < runs.length; i++) {
+ runs[i] = BidiWrapper.ubidi_getRun(pBidi, i);
+ }
+ }
+
+ direction = BidiWrapper.ubidi_getDirection(pBidi);
+ }
+
+ private int baseLevel;
+
+ private int length;
+
+ private byte[] offsetLevel;
+
+ private BidiRun[] runs;
+
+ private int direction;
+
+ /**
+ * Return whether the base level is from left to right.
+ *
+ * @return true if the base level is from left to right.
+ */
+ public boolean baseIsLeftToRight() {
+ return baseLevel % 2 == 0 ? true : false;
+ }
+
+ /**
+ * Create a new Bidi object containing the infomation of one line from this
+ * object.
+ *
+ * @param lineStart
+ * the start offset of the line.
+ * @param lineLimit
+ * the limit of the line.
+ * @return the new line Bidi object. In this new object, the indices will
+ * range from 0 to (limit - start - 1).
+ */
+ public Bidi createLineBidi(int lineStart, int lineLimit) {
+ char[] text = new char[this.length];
+ Arrays.fill(text, 'a');
+ byte[] embeddings = new byte[this.length];
+ for (int i = 0; i < embeddings.length; i++) {
+ embeddings[i] = (byte) -this.offsetLevel[i];
+ }
+
+ int dir = this.baseIsLeftToRight() ? Bidi.DIRECTION_LEFT_TO_RIGHT
+ : Bidi.DIRECTION_RIGHT_TO_LEFT;
+
+ long parent = createUBiDi(text, 0, embeddings, 0, this.length, dir);
+
+ long line = BidiWrapper.ubidi_setLine(parent, lineStart, lineLimit);
+ Bidi result = new Bidi(line);
+ BidiWrapper.ubidi_close(line);
+ BidiWrapper.ubidi_close(parent);
+ return result;
+ }
+
+ /**
+ * Return the base level.
+ *
+ * @return the int value of the base level.
+ */
+ public int getBaseLevel() {
+ return baseLevel;
+ }
+
+ /**
+ * Return the length of the text in the Bidi object.
+ *
+ * @return the int value of the length.
+ */
+ public int getLength() {
+ return length;
+ }
+
+ /**
+ * Return the level of a specified character.
+ *
+ * @param offset
+ * the offset of the character.
+ * @return the int value of the evel.
+ */
+ public int getLevelAt(int offset) {
+ try {
+ return offsetLevel[offset] & ~BidiWrapper.UBIDI_LEVEL_OVERRIDE;
+ } catch (RuntimeException e) {
+ return baseLevel;
+ }
+ }
+
+ /**
+ * Return the number of runs in the bidirectional text.
+ *
+ * @return the int value of runs, at least 1.
+ */
+ public int getRunCount() {
+ return runs.length;
+ }
+
+ /**
+ * Return the level of a specified run.
+ *
+ * @param run
+ * the index of the run.
+ * @return the level of the run.
+ */
+ public int getRunLevel(int run) {
+ return runs[run].getLevel();
+ }
+
+ /**
+ * Return the limit offset of a specified run.
+ *
+ * @param run
+ * the index of the run.
+ * @return the limit offset of the run.
+ */
+ public int getRunLimit(int run) {
+ return runs[run].getLimit();
+ }
+
+ /**
+ * Return the start offset of a specified run.
+ *
+ * @param run
+ * the index of the run.
+ * @return the start offset of the run.
+ */
+ public int getRunStart(int run) {
+ return runs[run].getStart();
+ }
+
+ /**
+ * Return whether the text is from left to right, that is, both the base
+ * direction and the text direction is from left to right.
+ *
+ * @return true if the text is from left to right.
+ */
+ public boolean isLeftToRight() {
+ return direction == BidiWrapper.UBiDiDirection_UBIDI_LTR;
+ }
+
+ /**
+ * Return whether the text direction is mixed.
+ *
+ * @return true if the text direction is mixed.
+ */
+ public boolean isMixed() {
+ return direction == BidiWrapper.UBiDiDirection_UBIDI_MIXED;
+ }
+
+ /**
+ * Return whether the text is from right to left, that is, both the base
+ * direction and the text direction is from right to left.
+ *
+ * @return true if the text is from right to left.
+ */
+ public boolean isRightToLeft() {
+ return direction == BidiWrapper.UBiDiDirection_UBIDI_RTL;
+ }
+
+ /**
+ * Reorder a range of objects according to their spefied levels. This is a
+ * convenience function that does not use a Bidi object. The range of
+ * objects at index from objectStart to objectStart + count will be
+ * reordered according to the range of levels at index from levelStart to
+ * levelStart + count.
+ *
+ * @param levels
+ * the level array, which is already determined.
+ * @param levelStart
+ * the start offset of the range of the levels.
+ * @param objects
+ * the object array to reoeder.
+ * @param objectStart
+ * the start offset of the range of objects.
+ * @param count
+ * the count of the range of objects to reorder.
+ */
+ public static void reorderVisually(byte[] levels, int levelStart,
+ Object[] objects, int objectStart, int count) {
+ try {
+ byte[] realLevels = new byte[count];
+ System.arraycopy(levels, levelStart, realLevels, 0, count);
+
+ int[] indices = BidiWrapper.ubidi_reorderVisual(realLevels, count);
+
+ LinkedList result = new LinkedList();
+ for (int i = 0; i < count; i++) {
+ result.addLast(objects[objectStart + indices[i]]);
+ }
+
+ System.arraycopy(result.toArray(), 0, objects, objectStart, count);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Return whether a range of characters of a text requires a Bidi object to
+ * display properly.
+ *
+ * @param text
+ * the char array of the text.
+ * @param start
+ * the start offset of the range of characters.
+ * @param limit
+ * the limit offset of the range of characters.
+ * @return true if the range of characters requires a Bidi object.
+ */
+ public static boolean requiresBidi(char[] text, int start, int limit) {
+ if (limit < 0 || start >= limit) {
+ return false;
+ } else if (start < 0 || start > text.length || limit > text.length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ Bidi bidi = new Bidi(text, start, null, 0, limit - start, 0);
+
+ if (bidi.isLeftToRight()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Return the internal message of the Bidi object, used in debugging.
+ *
+ * @return a string containing the internal messsage.
+ */
+ public String toString() {
+ // simply return nothing
+ return "";
+ }
+}
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/BreakIterator.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/BreakIterator.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/BreakIterator.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/BreakIterator.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,365 @@
+/* Copyright 2005 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.text;
+
+
+import java.util.Locale;
+
+/**
+ * This class is used to locate the boundaries of text. Instance of this class
+ * can be got by some factory methods:
+ * <ul>
+ * <li>
+ * <code>getCharacterIntance()<code> returns a BreakIterator that iterate the
+ * logical characters without worrying about how the character is stored. For
+ * example, some character may be stored in more than one Unicode code point
+ * according to Unicode specification, this character can handle the logical
+ * characters with multi code points.</li>
+ * <li>
+ * <code>getWordIntance()<code> returns a <code>BreakIterator</code> that
+ * iterate the word-breaks. The beginning and end of each word(including numbers)
+ * is treated as boundary position. Whitespace and punctuation are kept separate
+ * from real words.</li>
+ * <li>
+ * <code>getSentenceInstance()</code> returns a BreakIterator that iterate the
+ * sentence-breaks.</li>
+ * <li><code>getLineInstance()</code> retuens a BreakIterator that iterate the
+ * line-breaks which can be used to wrap lines. This iterator can handle whitespaces,
+ * hyphens and punctuations.
+ * </ul>
+ *
+ * <code>BreakIterator</code> uses <code>CharacterIterator</code> to perform the
+ * analysis, so that any storage which provides <code>CharacterIterator</code>
+ * interface.
+ *
+ * @see CharacterIterator
+ */
+public abstract class BreakIterator implements Cloneable {
+
+ /*
+ * -----------------------------------------------------------------------
+ * constantants
+ * -----------------------------------------------------------------------
+ */
+ /**
+ * This constant is returned by iterate methods like previous() or next() if
+ * they have returned all valid boundaries.
+ */
+ public static final int DONE = -1;
+
+ /*
+ * -----------------------------------------------------------------------
+ * variables
+ * -----------------------------------------------------------------------
+ */
+ // the wrapped icu implementation
+ com.ibm.icu.text.BreakIterator wrapped;
+
+ /*
+ * -----------------------------------------------------------------------
+ * constructors
+ * -----------------------------------------------------------------------
+ */
+ /**
+ * Default constructor, just for invocation by subclass.
+ */
+ protected BreakIterator() {
+ super();
+ }
+
+ /*
+ * wrapping constructor
+ */
+ BreakIterator(com.ibm.icu.text.BreakIterator iterator) {
+ wrapped = iterator;
+ }
+
+ /*
+ * -----------------------------------------------------------------------
+ * methods
+ * -----------------------------------------------------------------------
+ */
+ /**
+ * Return all supported locales.
+ *
+ * @return all supported locales
+ */
+ public static Locale[] getAvailableLocales() {
+ return com.ibm.icu.text.BreakIterator.getAvailableLocales();
+ }
+
+ /**
+ * Return a new instance of BreakIterator used to iterate characters using
+ * default locale.
+ *
+ * @return a new instance of BreakIterator used to iterate characters using
+ * default locale.
+ */
+ public static BreakIterator getCharacterInstance() {
+ return new RuleBasedBreakIterator(com.ibm.icu.text.BreakIterator
+ .getCharacterInstance());
+ }
+
+ /**
+ * Return a new instance of BreakIterator used to iterate characters using
+ * given locale.
+ *
+ * @param where
+ * the given locale
+ * @return a new instance of BreakIterator used to iterate characters using
+ * given locale.
+ */
+ public static BreakIterator getCharacterInstance(Locale where) {
+ return new RuleBasedBreakIterator(com.ibm.icu.text.BreakIterator
+ .getCharacterInstance(where));
+ }
+
+ /**
+ * Return a new instance of BreakIterator used to iterate line-breaks using
+ * default locale.
+ *
+ * @return a new instance of BreakIterator used to iterate line-breaks using
+ * default locale.
+ */
+ public static BreakIterator getLineInstance() {
+ return new RuleBasedBreakIterator(com.ibm.icu.text.BreakIterator
+ .getLineInstance());
+ }
+
+ /**
+ * Return a new instance of BreakIterator used to iterate line-breaks using
+ * given locale.
+ *
+ * @param where
+ * the given locale
+ * @return a new instance of BreakIterator used to iterate line-breaks using
+ * given locale.
+ */
+ public static BreakIterator getLineInstance(Locale where) {
+ return new RuleBasedBreakIterator(com.ibm.icu.text.BreakIterator
+ .getLineInstance(where));
+ }
+
+ /**
+ * Return a new instance of BreakIterator used to iterate sentense-breaks
+ * using default locale.
+ *
+ * @return a new instance of BreakIterator used to iterate sentense-breaks
+ * using default locale.
+ */
+ public static BreakIterator getSentenceInstance() {
+ return new RuleBasedBreakIterator(com.ibm.icu.text.BreakIterator
+ .getSentenceInstance());
+ }
+
+ /**
+ * Return a new instance of BreakIterator used to iterate sentense-breaks
+ * using given locale.
+ *
+ * @param where
+ * the given locale
+ * @return a new instance of BreakIterator used to iterate sentense-breaks
+ * using given locale.
+ */
+ public static BreakIterator getSentenceInstance(Locale where) {
+ return new RuleBasedBreakIterator(com.ibm.icu.text.BreakIterator
+ .getSentenceInstance(where));
+ }
+
+ /**
+ * Return a new instance of BreakIterator used to iterate word-breaks using
+ * default locale.
+ *
+ * @return a new instance of BreakIterator used to iterate word-breaks using
+ * default locale.
+ */
+ public static BreakIterator getWordInstance() {
+ return new RuleBasedBreakIterator(com.ibm.icu.text.BreakIterator
+ .getWordInstance());
+ }
+
+ /**
+ * Return a new instance of BreakIterator used to iterate word-breaks using
+ * given locale.
+ *
+ * @param where
+ * the given locale
+ * @return a new instance of BreakIterator used to iterate word-breaks using
+ * given locale.
+ */
+ public static BreakIterator getWordInstance(Locale where) {
+ return new RuleBasedBreakIterator(com.ibm.icu.text.BreakIterator
+ .getSentenceInstance(where));
+ }
+
+ /**
+ * Return true if the given offset is a boundary position. If this method
+ * returns true, the current iteration position is set to the given
+ * position; if the function returns false, the current iteration position
+ * is set as though following() had been called.
+ *
+ * @param offset
+ * the given offset to check
+ * @return true if the given offset is a boudary postion
+ */
+ public boolean isBoundary(int offset) {
+ return wrapped.isBoundary(offset);
+ }
+
+ /**
+ * Return the postion of last boundary precede the given offset, and set
+ * current postion to returned value, or <code>DONE</code> if the given
+ * offset specifies the starting position.
+ * <p>
+ * <code>IllegalArgumentException</code> will be thrown if given offset is
+ * invalid.
+ * </p>
+ *
+ * @param offset
+ * the given start position to be searched for
+ * @return the postion of last boundary precede the given offset
+ */
+ public int preceding(int offset) {
+ return wrapped.preceding(offset);
+ }
+
+ /**
+ * Set the new text string to be analyzed, the current position will be
+ * reset to beginning of this new string, and the old string will lost.
+ *
+ * @param newText
+ * the new text string to be analyzed
+ */
+ public void setText(String newText) {
+ wrapped.setText(newText);
+ }
+
+ /*
+ * -----------------------------------------------------------------------
+ * abstract methods
+ * -----------------------------------------------------------------------
+ */
+ /**
+ * Return this iterator's current position.
+ *
+ * @return this iterator's current position
+ */
+ public abstract int current();
+
+ /**
+ * Set this iterator's current position to the first boundary, and return
+ * this postion.
+ *
+ * @return the position of first boundary
+ */
+ public abstract int first();
+
+ /**
+ * Set the position of the first boundary following the given offset, and
+ * return this position. If there is no boundary after the given offset,
+ * return DONE.
+ * <p>
+ * <code>IllegalArgumentException</code> will be thrown if given offset is
+ * invalid.
+ * </p>
+ *
+ * @param offset
+ * the given position to be searched for
+ * @return the position of the first boundary following the given offset
+ */
+ public abstract int following(int offset);
+
+ /**
+ * Return a <code>CharacterIterator</code> which represents the text being
+ * analyzed. Please note that the returned value is probablly the internal
+ * iterator used by this object, so that if the invoker want to modify the
+ * status of the returned iterator, a clone operation at first is
+ * recommended.
+ *
+ * @return a <code>CharacterIterator</code> which represents the text
+ * being analyzed.
+ */
+ public abstract CharacterIterator getText();
+
+ /**
+ * Set this iterator's current position to the last boundary, and return
+ * this postion.
+ *
+ * @return the position of last boundary
+ */
+ public abstract int last();
+
+ /**
+ * Set this iterator's current position to the next boundary after current
+ * position, and return this postion. Return <code>DONE</code> if no
+ * boundary found after current position.
+ *
+ * @return the position of last boundary
+ */
+ public abstract int next();
+
+ /**
+ * Set this iterator's current position to the next boundary after the given
+ * position, and return this postion. Return <code>DONE</code> if no
+ * boundary found after the given position.
+ *
+ * @param n
+ * the given position.
+ * @return the position of last boundary
+ */
+ public abstract int next(int n);
+
+ /**
+ * Set this iterator's current position to the previous boundary before
+ * current position, and return this postion. Return <code>DONE</code> if
+ * no boundary found before current position.
+ *
+ * @return the position of last boundary
+ */
+ public abstract int previous();
+
+ /**
+ * Set new text to be analyzed by given <code>CharacterIterator</code>.
+ * The position will be reset to the beginning of the new text, and other
+ * status of this iterator will be kept.
+ *
+ * @param newText
+ * the given <code>CharacterIterator</code> refer to the text
+ * to be analyzed
+ */
+ public abstract void setText(CharacterIterator newText);
+
+ /*
+ * -----------------------------------------------------------------------
+ * methods override Object
+ * -----------------------------------------------------------------------
+ */
+ /**
+ * Create copy of this iterator, all status including current position is
+ * kept.
+ *
+ * @return copy of this iterator
+ */
+ public Object clone() {
+ try {
+ BreakIterator cloned = (BreakIterator) super.clone();
+ cloned.wrapped = (com.ibm.icu.text.BreakIterator) wrapped.clone();
+ return cloned;
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError(e.getMessage());
+ }
+ }
+}
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/CharacterIterator.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/CharacterIterator.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/CharacterIterator.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/CharacterIterator.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,112 @@
+/* Copyright 1998, 2004 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.text;
+
+
+/**
+ * CharacterIterator is used to sequence over a group of characters. The
+ * iteration starts at the begin index in the group of character and continues
+ * to one index before the end index.
+ */
+public interface CharacterIterator extends Cloneable {
+
+ /**
+ * A constant which indicates there is no character.
+ */
+ public static char DONE = '\uffff';
+
+ /**
+ * Answers a new CharacterIterator with the same properties.
+ *
+ * @return a shallow copy of this CharacterIterator
+ *
+ * @see java.lang.Cloneable
+ */
+ public Object clone();
+
+ /**
+ * Answers the character at the current index.
+ *
+ * @return the current character, or DONE if the current index is past the
+ * end
+ */
+ public char current();
+
+ /**
+ * Sets the current position to the begin index and answers the character at
+ * the begin index.
+ *
+ * @return the character at the begin index
+ */
+ public char first();
+
+ /**
+ * Answers the begin index.
+ *
+ * @return the index of the first character to iterate
+ */
+ public int getBeginIndex();
+
+ /**
+ * Answers the end index.
+ *
+ * @return the index one past the last character to iterate
+ */
+ public int getEndIndex();
+
+ /**
+ * Answers the current index.
+ *
+ * @return the current index
+ */
+ public int getIndex();
+
+ /**
+ * Sets the current position to the end index - 1 and answers the character
+ * at the current position.
+ *
+ * @return the character before the end index
+ */
+ public char last();
+
+ /**
+ * Increments the current index and returns the character at the new index.
+ *
+ * @return the character at the next index, or DONE if the next index is
+ * past the end
+ */
+ public char next();
+
+ /**
+ * Decrements the current index and returns the character at the new index.
+ *
+ * @return the character at the previous index, or DONE if the previous
+ * index is past the beginning
+ */
+ public char previous();
+
+ /**
+ * Sets the current index.
+ *
+ * @return the character at the new index, or DONE if the index is past the
+ * end
+ *
+ * @exception IllegalArgumentException
+ * when the new index is less than the begin index or greater
+ * than the end index
+ */
+ public char setIndex(int location);
+}
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/ChoiceFormat.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/ChoiceFormat.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/ChoiceFormat.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/ChoiceFormat.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,389 @@
+/* Copyright 1998, 2004 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.text;
+
+
+import java.util.Arrays;
+import java.util.Vector;
+
+/**
+ * ChoiceFormat is used to assocate strings with ranges of double values. The
+ * strings and ranges are either specified using arrays or with a pattern which
+ * is parsed to determine the Strings and ranges.
+ */
+
+public class ChoiceFormat extends NumberFormat {
+
+ static final long serialVersionUID = 1795184449645032964L;
+
+ private double[] choiceLimits;
+
+ private String[] choiceFormats;
+
+ /**
+ * Constructs a new ChoiceFormat with the specified ranges and associated
+ * strings.
+ *
+ * @param limits
+ * an array of double, the ranges are greater or equal to the
+ * value in lower index up to less than the value in the next
+ * higher index. The bounds of the lowest and highest indexes are
+ * negative and positive infinity.
+ * @param formats
+ * the strings associated with the ranges. The lower bound of the
+ * associated range is at the same index as the string.
+ */
+ public ChoiceFormat(double[] limits, String[] formats) {
+ setChoices(limits, formats);
+ }
+
+ /**
+ * Constructs a new ChoiceFormat with the strings and ranges parsed from the
+ * specified pattern.
+ *
+ * @param template
+ * the pattern of strings and ranges
+ *
+ * @exception IllegalArgumentException
+ * then an error occurs parsing the pattern
+ */
+ public ChoiceFormat(String template) {
+ applyPattern(template);
+ }
+
+ /**
+ * Parses the pattern to determine new strings and ranges for this
+ * ChoiceFormat.
+ *
+ * @param template
+ * the pattern of strings and ranges
+ *
+ * @exception IllegalArgumentException
+ * then an error occurs parsing the pattern
+ */
+ public void applyPattern(String template) {
+ boolean first = true;
+ double[] limits = new double[5];
+ Vector formats = new Vector();
+ int length = template.length(), limitCount = 0, index = 0;
+ StringBuffer buffer = new StringBuffer();
+ NumberFormat format = NumberFormat.getInstance();
+ ParsePosition position = new ParsePosition(0);
+ while (true) {
+ index = skipWhitespace(template, index);
+ if (index >= length) {
+ if (limitCount == limits.length)
+ choiceLimits = limits;
+ else {
+ choiceLimits = new double[limitCount];
+ System.arraycopy(limits, 0, choiceLimits, 0, limitCount);
+ }
+ choiceFormats = new String[formats.size()];
+ for (int i = 0; i < formats.size(); i++)
+ choiceFormats[i] = (String) formats.elementAt(i);
+ return;
+ }
+
+ position.setIndex(index);
+ Number value = format.parse(template, position);
+ index = skipWhitespace(template, position.getIndex());
+ if (position.getErrorIndex() != -1 || index >= length)
+ throw new IllegalArgumentException();
+ char ch = template.charAt(index++);
+ if (limitCount == limits.length) {
+ double[] newLimits = new double[limitCount * 2];
+ System.arraycopy(limits, 0, newLimits, 0, limitCount);
+ limits = newLimits;
+ }
+ double next;
+ switch (ch) {
+ case '#':
+ case '\u2264':
+ next = value.doubleValue();
+ break;
+ case '<':
+ if (first)
+ throw new IllegalArgumentException();
+ next = nextDouble(value.doubleValue());
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ first = false;
+ if (limitCount > 0 && next <= limits[limitCount - 1])
+ throw new IllegalArgumentException();
+ buffer.setLength(0);
+ position.setIndex(index);
+ upTo(template, position, buffer, '|');
+ index = position.getIndex();
+ limits[limitCount++] = next;
+ formats.addElement(buffer.toString());
+ }
+ }
+
+ /**
+ * Answers a new instance of ChoiceFormat with the same ranges and strings
+ * as this ChoiceFormat.
+ *
+ * @return a shallow copy of this ChoiceFormat
+ *
+ * @see java.lang.Cloneable
+ */
+ public Object clone() {
+ ChoiceFormat clone = (ChoiceFormat) super.clone();
+ clone.choiceLimits = (double[]) choiceLimits.clone();
+ clone.choiceFormats = (String[]) choiceFormats.clone();
+ return clone;
+ }
+
+ /**
+ * Compares the specified object to this ChoiceFormat and answer if they are
+ * equal. The object must be an instance of ChoiceFormat and have the same
+ * limits and formats.
+ *
+ * @param object
+ * the object to compare with this object
+ * @return true if the specified object is equal to this ChoiceFormat, false
+ * otherwise
+ *
+ * @see #hashCode
+ */
+ public boolean equals(Object object) {
+ if (this == object)
+ return true;
+ if (!(object instanceof ChoiceFormat))
+ return false;
+ ChoiceFormat choice = (ChoiceFormat) object;
+ return Arrays.equals(choiceLimits, choice.choiceLimits)
+ && Arrays.equals(choiceFormats, choice.choiceFormats);
+ }
+
+ /**
+ * Appends to the specified StringBuffer the string associated with the
+ * range in which the specified double value fits.
+ *
+ * @param value
+ * the double to format
+ * @param buffer
+ * the StringBuffer
+ * @param field
+ * a FieldPosition which is ignored
+ * @return the StringBuffer parameter <code>buffer</code>
+ */
+ public StringBuffer format(double value, StringBuffer buffer,
+ FieldPosition field) {
+ if (Double.isNaN(value)
+ || (choiceLimits.length > 1 && value < choiceLimits[1]))
+ return buffer.append(choiceFormats[0]);
+ for (int i = 2; i < choiceLimits.length; i++)
+ if (value >= choiceLimits[i - 1] && value < choiceLimits[i])
+ return buffer.append(choiceFormats[i - 1]);
+ return buffer.append(choiceFormats[choiceFormats.length - 1]);
+ }
+
+ /**
+ * Appends to the specified StringBuffer the string associated with the
+ * range in which the specified long value fits.
+ *
+ * @param value
+ * the long to format
+ * @param buffer
+ * the StringBuffer
+ * @param field
+ * a FieldPosition which is ignored
+ * @return the StringBuffer parameter <code>buffer</code>
+ */
+ public StringBuffer format(long value, StringBuffer buffer,
+ FieldPosition field) {
+ return format((double) value, buffer, field);
+ }
+
+ /**
+ * Answers the Strings associated with the ranges of this ChoiceFormat.
+ *
+ * @return an array of String
+ */
+ public Object[] getFormats() {
+ return choiceFormats;
+ }
+
+ /**
+ * Answers the ranges of this ChoiceFormat.
+ *
+ * @return an array of double, the ranges are greater or equal to the value
+ * in lower index up to less than the value in the next higher
+ * index. The bounds of the lowest and highest indexes are negative
+ * and positive infinity.
+ */
+ public double[] getLimits() {
+ return choiceLimits;
+ }
+
+ /**
+ * Answers an integer hash code for the receiver. Objects which are equal
+ * answer the same value for this method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+ public int hashCode() {
+ int hashCode = 0;
+ for (int i = 0; i < choiceLimits.length; i++) {
+ long v = Double.doubleToLongBits(choiceLimits[i]);
+ hashCode += (int) (v ^ (v >>> 32)) + choiceFormats[i].hashCode();
+ }
+ return hashCode;
+ }
+
+ /**
+ * Answers the double value which is closest to the specified double but
+ * larger.
+ *
+ * @param value
+ * a double value
+ * @return the next larger double value
+ */
+ public static final double nextDouble(double value) {
+ if (value == Double.POSITIVE_INFINITY)
+ return value;
+ long bits;
+ // Handle -0.0
+ if (value == 0)
+ bits = 0;
+ else
+ bits = Double.doubleToLongBits(value);
+ return Double.longBitsToDouble(value < 0 ? bits - 1 : bits + 1);
+ }
+
+ /**
+ * Answers the double value which is closest to the specified double but
+ * either larger or smaller as specified.
+ *
+ * @param value
+ * a double value
+ * @param increment
+ * true to get a larger value, false to get a smaller value
+ * @return the next larger or smaller double value
+ */
+ public static double nextDouble(double value, boolean increment) {
+ return increment ? nextDouble(value) : previousDouble(value);
+ }
+
+ /**
+ * Parse a Double from the specified String starting at the index specified
+ * by the ParsePosition. The String is compared to the strings of this
+ * ChoiceFormat and if a match occurs, the answer is the lower bound of the
+ * corresponding range. If the string is successfully parsed, the index of
+ * the ParsePosition is updated to the index following the parsed text.
+ *
+ * @param string
+ * the String to parse
+ * @param position
+ * the ParsePosition, updated on return with the index following
+ * the parsed text, or on error the index is unchanged and the
+ * error index is set to the index where the error occurred
+ * @return a Double resulting from the parse, or Double.NaN if there is an
+ * error
+ */
+ public Number parse(String string, ParsePosition position) {
+ int offset = position.getIndex();
+ for (int i = 0; i < choiceFormats.length; i++) {
+ if (string.startsWith(choiceFormats[i], offset)) {
+ position.setIndex(offset + choiceFormats[i].length());
+ return new Double(choiceLimits[i]);
+ }
+ }
+ position.setErrorIndex(offset);
+ return new Double(Double.NaN);
+ }
+
+ /**
+ * Answers the double value which is closest to the specified double but
+ * smaller.
+ *
+ * @param value
+ * a double value
+ * @return the next smaller double value
+ */
+ public static final double previousDouble(double value) {
+ if (value == Double.NEGATIVE_INFINITY)
+ return value;
+ long bits;
+ // Handle 0.0
+ if (value == 0)
+ bits = 0x8000000000000000L;
+ else
+ bits = Double.doubleToLongBits(value);
+ return Double.longBitsToDouble(value <= 0 ? bits + 1 : bits - 1);
+ }
+
+ /**
+ * Sets the ranges and associated strings of this ChoiceFormat.
+ *
+ * @param limits
+ * an array of double, the ranges are greater or equal to the
+ * value in lower index up to less than the value in the next
+ * higher index. The bounds of the lowest and highest indexes are
+ * negative and positive infinity.
+ * @param formats
+ * the strings associated with the ranges. The lower bound of the
+ * range is at the same index as the string.
+ */
+ public void setChoices(double[] limits, String[] formats) {
+ if (limits.length != formats.length)
+ throw new IllegalArgumentException();
+ choiceLimits = limits;
+ choiceFormats = formats;
+ }
+
+ private int skipWhitespace(String string, int index) {
+ int length = string.length();
+ while (index < length && Character.isWhitespace(string.charAt(index)))
+ index++;
+ return index;
+ }
+
+ /**
+ * Answers the pattern of this ChoiceFormat which specified the ranges and
+ * their associated strings.
+ *
+ * @return the pattern
+ */
+ public String toPattern() {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < choiceLimits.length; i++) {
+ String previous = String.valueOf(previousDouble(choiceLimits[i]));
+ String limit = String.valueOf(choiceLimits[i]);
+ if (previous.length() < limit.length()) {
+ buffer.append(previous);
+ buffer.append('<');
+ } else {
+ buffer.append(limit);
+ buffer.append('#');
+ }
+ boolean quote = (choiceFormats[i].indexOf('|') != -1);
+ if (quote)
+ buffer.append('\'');
+ buffer.append(choiceFormats[i]);
+ if (quote)
+ buffer.append('\'');
+ buffer.append('|');
+ }
+ buffer.setLength(buffer.length() - 1);
+ return buffer.toString();
+ }
+}
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/CollationElementIterator.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/CollationElementIterator.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/CollationElementIterator.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/CollationElementIterator.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,246 @@
+/* Copyright 2005 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.text;
+
+
+/**
+ * <p>
+ * <code>CollationElementIterator</code> is created by a
+ * <code>RuleBasedCollator</code> to iterate through a string. The return result
+ * of each iteration is a 32-bit collation element that defines the ordering
+ * priority of the next character or sequence of characters in the source
+ * string.
+ * </p>
+ * <p>
+ * For illustration, consider the following in Spanish:
+ * </p>
+ *
+ * <p>
+ * <code>
+ * "ca" -> the first collation element is collation_element('c') and second
+ * collation element is collation_element('a').
+ * </code>
+ * </p>
+ *
+ * <p>
+ * <code>
+ * Since "ch" in Spanish sorts as one entity, the below example returns one
+ * collation element for the two characters 'c' and 'h'
+ * </code>
+ * </p>
+ *
+ * <p>
+ * <code>
+ * "cha" -> the first collation element is collation_element('ch') and second
+ * collation element is collation_element('a').
+ * </code>
+ * </p>
+ * <p>
+ * And in German,
+ * </p>
+ *
+ * <p>
+ * <code>
+ * Since the character '�' is a composed character of 'a' and 'e', the iterator
+ * returns two collation elements for the single character '�'
+ * </code>
+ * </p>
+ * <p>
+ * <code>
+ * "�b" -> the first
+ * collation element is collation_element('a'), the second collation element is
+ * collation_element('e'), and the third collation element is
+ * collation_element('b').
+ * </code>
+ * </p>
+ *
+ */
+public final class CollationElementIterator {
+
+ /**
+ * This constant is returned by the iterator in the methods
+ * <code>next()</code> and <code>previous()</code> when the end or the
+ * beginning of the source string has been reached, and there are no more
+ * valid collation elements to return.
+ */
+ public static final int NULLORDER = -1;
+
+ private com.ibm.icu.text.CollationElementIterator icuIterator;
+
+ CollationElementIterator(com.ibm.icu.text.CollationElementIterator iterator) {
+ this.icuIterator = iterator;
+ }
+
+ /**
+ * Obtains the maximum length of any expansion sequence that ends with the
+ * specified collation element. If there is no expansion with this collation
+ * element as the last element, returns <code>1</code>.
+ *
+ * @param order
+ * a collation element that has been previously obtained from
+ * a call to either the {@link #next()} or {@link #previous()}
+ * method.
+ * @return the maximum length of any expansion sequence ending with the
+ * specified collation element.
+ */
+ public int getMaxExpansion(int order) {
+ return this.icuIterator.getMaxExpansion(order);
+ }
+
+ /**
+ * Obtains the character offset in the source string corresponding to the
+ * next collation element. This value could be any of: <ui>
+ * <li>The index of the first character in the source string that matches
+ * the value of the next collation element. (This means that if
+ * setOffset(offset) sets the index in the middle of a contraction,
+ * getOffset() returns the index of the first character in the contraction,
+ * which may not be equal to the original offset that was set. Hence calling
+ * getOffset() immediately after setOffset(offset) does not guarantee that
+ * the original offset set will be returned.)</li>
+ * <li>If normalization is on, the index of the immediate subsequent
+ * character, or composite character with the first character, having a
+ * combining class of 0.</li>
+ * <li>The length of the source string, if iteration has reached the end.
+ * </li>
+ * <ui>
+ *
+ * @return The position of the collation element in the source string that
+ * will be returned in the next invocation of the {@link #next()} method.
+ */
+ public int getOffset() {
+ return this.icuIterator.getOffset();
+ }
+
+ /**
+ * Obtains the next collation element in the source string.
+ *
+ * @return the next collation element or <code>NULLORDER</code> if the end
+ * of the iteration has been reached.
+ */
+ public int next() {
+ return this.icuIterator.next();
+ }
+
+ /**
+ * Obtains the previous collation element in the source string.
+ *
+ * @return the previous collation element, or <code>NULLORDER</code> when
+ * the start of the iteration has been reached.
+ */
+ public int previous() {
+ return this.icuIterator.previous();
+ }
+
+ /**
+ * Obtains the primary order of the specified collation element, i.e. the
+ * first 16 bits. This value is unsigned.
+ *
+ * @param order
+ * @return the element's 16 bits primary order.
+ */
+ public static final int primaryOrder(int order) {
+ return com.ibm.icu.text.CollationElementIterator.primaryOrder(order);
+ }
+
+ /**
+ * Repositions the cursor to point at the first element of the current
+ * string. The next call to <code>next()</code> or <code>previous()</code>
+ * will return the first and last collation element in the string,
+ * respectively.
+ * <p>
+ * If the <code>RuleBasedCollator</code> used by this iterator has had its
+ * attributes changed, calling <code>reset()</code> will reinitialize the
+ * iterator to use the new attributes.
+ * </p>
+ */
+ public void reset() {
+ this.icuIterator.reset();
+ }
+
+ /**
+ * Obtains the secondary order of the specified collation element, i.e. the
+ * 16th to 23th bits, inclusive. This value is unsigned.
+ *
+ * @param order
+ * @return the 8 bit secondary order of the element
+ */
+ public static final short secondaryOrder(int order) {
+ return (short) com.ibm.icu.text.CollationElementIterator
+ .secondaryOrder(order);
+ }
+
+ /**
+ * Points the iterator at the collation element associated with the
+ * character in the source string which is found at the supplied offset.
+ * After this call completes, an invocation of the {@link #next()} method
+ * will return this collation element.
+ * <p>
+ * If <code>newOffset</code> corresponds to a character which is part of a
+ * sequence that maps to a single collation element the iterator is adjusted
+ * to the start of that sequence. As a result of this, any subsequent call
+ * made to <code>getOffset()</code> may not return the same value set by
+ * this method.
+ * </p>
+ * <p>
+ * If the decomposition mode is on, and offset is in the middle of a
+ * decomposible range of source text, the iterator may not return a correct
+ * result for the next forwards or backwards iteration. The user must ensure
+ * that the offset is not in the middle of a decomposible range.
+ * </p>
+ *
+ * @param newOffset
+ * the character offset into the original source string to set.
+ * Note that this is not an offset into the corresponding
+ * sequence of collation elements.
+ */
+ public void setOffset(int newOffset) {
+ this.icuIterator.setOffset(newOffset);
+ }
+
+ /**
+ * Sets a new source string interator for iteration, and reset the offset to
+ * the beginning of the text.
+ *
+ * @param source
+ * the new source string iterator for iteration.
+ */
+ public void setText(CharacterIterator source) {
+ this.icuIterator.setText(source);
+ }
+
+ /**
+ * Sets a new source string for iteration, and reset the offset to the
+ * beginning of the text.
+ *
+ * @param source
+ * the new source string for iteration
+ */
+ public void setText(String source) {
+ this.icuIterator.setText(source);
+ }
+
+ /**
+ * Obtains the tertiary order of the specified collation element, i.e. the
+ * last 8 bits. This value is unsigned.
+ *
+ * @param order
+ * @return the 8 bits tertiary order of the element
+ */
+ public static final short tertiaryOrder(int order) {
+ return (short) com.ibm.icu.text.CollationElementIterator
+ .tertiaryOrder(order);
+ }
+}
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/CollationKey.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/CollationKey.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/CollationKey.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/CollationKey.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,116 @@
+/* Copyright 2005 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.text;
+
+
+/**
+ * CollationKey represents the collation order of a particular String for a
+ * specific Collator. CollationKeys can be compared to determine the relative
+ * ordering of their source Strings. This is useful when the Strings must be
+ * compared multiple times, as in sorting.
+ */
+public final class CollationKey implements Comparable {
+
+ private String source;
+
+ private com.ibm.icu.text.CollationKey icuKey;
+
+ CollationKey(String source, com.ibm.icu.text.CollationKey key) {
+ this.source = source;
+ this.icuKey = key;
+ }
+
+ /**
+ * Compare the receiver to the specified CollationKey to determine the
+ * relative ordering.
+ *
+ * @param value
+ * a CollationKey
+ * @return an int < 0 if this CollationKey is less than the specified
+ * CollationKey, 0 if they are equal, and > 0 if this CollationKey
+ * is greater
+ */
+ public int compareTo(CollationKey value) {
+ return icuKey.compareTo(value.icuKey);
+ }
+
+ /**
+ * Compare this CollationKey to the specified Object to determine the
+ * relative ordering.
+ *
+ * @param object
+ * an Object
+ * @return an int < 0 if this CollationKey is less than the specified
+ * CollationKey, 0 if they are equal, and > 0 if this CollationKey
+ * is greater
+ *
+ * @exception ClassCastException
+ * when object is not a CollationKey
+ */
+ public int compareTo(Object object) {
+ return icuKey.compareTo(((CollationKey) object).icuKey);
+ }
+
+ /**
+ * Compares the specified object to this CollationKey and answer if they are
+ * equal. The object must be an instance of CollationKey and have the same
+ * source string and collation key. The instances of CollationKey must have
+ * been created by the same Collator.
+ *
+ * @param object
+ * the object to compare with this object
+ * @return true if the specified object is equal to this CollationKey, false
+ * otherwise
+ *
+ * @see #hashCode
+ */
+ public boolean equals(Object object) {
+ if (!(object instanceof CollationKey))
+ return false;
+ CollationKey collationKey = (CollationKey) object;
+ return icuKey.equals(collationKey.icuKey);
+ }
+
+ /**
+ * Answer the String from which this CollationKey was created.
+ *
+ * @return a String
+ */
+ public String getSourceString() {
+ return this.source;
+ }
+
+ /**
+ * Answers an integer hash code for the receiver. Objects which are equal
+ * answer the same value for this method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+ public int hashCode() {
+ return icuKey.hashCode();
+ }
+
+ /**
+ * Answer the collation key as a byte array.
+ *
+ * @return an array of bytes
+ */
+ public byte[] toByteArray() {
+ return icuKey.toByteArray();
+ }
+}
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/Collator.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/Collator.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/Collator.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/text/src/java/text/Collator.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,358 @@
+/* Copyright 2005 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.text;
+
+
+import java.security.AccessController;
+import java.util.Comparator;
+import java.util.Locale;
+import java.util.Vector;
+
+import com.ibm.oti.util.PriviAction;
+
+/**
+ * Collator is an abstract class which is the root of classes which provide
+ * Locale specific String comparison to determine their ordering with respect to
+ * each other.
+ */
+public abstract class Collator implements Comparator, Cloneable {
+
+ static final int EQUAL = 0;
+
+ static final int GREATER = 1;
+
+ static final int LESS = -1;
+
+ /**
+ * Constant used to specify the decomposition rule.
+ */
+ public static final int NO_DECOMPOSITION = 0;
+
+ /**
+ * Constant used to specify the decomposition rule.
+ */
+ public static final int CANONICAL_DECOMPOSITION = 1;
+
+ /**
+ * Constant used to specify the decomposition rule.
+ */
+ public static final int FULL_DECOMPOSITION = 2;
+
+ /**
+ * Constant used to specify the collation strength.
+ */
+ public static final int PRIMARY = 0;
+
+ /**
+ * Constant used to specify the collation strength.
+ */
+ public static final int SECONDARY = 1;
+
+ /**
+ * Constant used to specify the collation strength.
+ */
+ public static final int TERTIARY = 2;
+
+ /**
+ * Constant used to specify the collation strength.
+ */
+ public static final int IDENTICAL = 3;
+
+ private static int CACHE_SIZE;
+
+ private static Vector cache = new Vector(CACHE_SIZE);
+
+ // Wrapper class of ICU4J Collator
+ com.ibm.icu.text.Collator icuColl;
+
+ static {
+ // CACHE_SIZE includes key and value, so needs to be double
+ String cacheSize = (String) AccessController
+ .doPrivileged(new PriviAction("collator.cache")); //$NON-NLS-1$
+ if (cacheSize != null) {
+ try {
+ CACHE_SIZE = Integer.parseInt(cacheSize);
+ } catch (NumberFormatException e) {
+ CACHE_SIZE = 6;
+ }
+ } else
+ CACHE_SIZE = 6;
+ }
+
+ Collator(com.ibm.icu.text.Collator wrapper) {
+ this.icuColl = wrapper;
+ }
+
+ /**
+ * Constructs a new instance of this Collator.
+ */
+ protected Collator() {
+ super();
+ }
+
+ /**
+ * Answers a new Collator with the same decomposition rule and strength
+ * value as this Collator.
+ *
+ * @return a shallow copy of this Collator
+ * @see java.lang.Cloneable
+ */
+ public Object clone() {
+ try {
+ Collator clone = (Collator) super.clone();
+ clone.icuColl = (com.ibm.icu.text.Collator) this.icuColl.clone();
+ return clone;
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Compares the two objects to determine their relative ordering. The
+ * objects must be Strings.
+ *
+ * @param object1
+ * the first String to compare
+ * @param object2
+ * the second String to compare
+ * @return an int < 0 if object1 is less than object2, 0 if they are equal,
+ * and > 0 if object1 is greater than object2
+ *
+ * @exception ClassCastException
+ * when the objects are not Strings
+ */
+ public int compare(Object object1, Object object2) {
+ return compare((String) object1, (String) object2);
+ }
+
+ /**
+ * Compares the two Strings to determine their relative ordering.
+ *
+ * @param string1
+ * the first String to compare
+ * @param string2
+ * the second String to compare
+ * @return an int < 0 if string1 is less than string2, 0 if they are equal,
+ * and > 0 if string1 is greater than string2
+ */
+ public abstract int compare(String string1, String string2);
+
+ /**
+ * Compares the specified object to this Collator and answer if they are
+ * equal. The object must be an instance of Collator and have the same
+ * strength and decomposition values.
+ *
+ * @param object
+ * the object to compare with this object
+ * @return true if the specified object is equal to this Collator, false
+ * otherwise
+ *
+ * @see #hashCode
+ */
+ public boolean equals(Object object) {
+ if (!(object instanceof Collator))
+ return false;
+ Collator collator = (Collator) object;
+ return this.icuColl == null ? collator.icuColl == null : this.icuColl
+ .equals(collator.icuColl);
+ }
+
+ /**
+ * Compares the two Strings using the collation rules to determine if they
+ * are equal.
+ *
+ * @param string1
+ * the first String to compare
+ * @param string2
+ * the second String to compare
+ * @return true if the strings are equal using the collation rules, false
+ * otherwise
+ */
+ public boolean equals(String string1, String string2) {
+ return compare(string1, string2) == 0;
+ }
+
+ /**
+ * Gets the list of installed Locales which support Collator.
+ *
+ * @return an array of Locale
+ */
+ public static Locale[] getAvailableLocales() {
+ return com.ibm.icu.text.Collator.getAvailableLocales();
+ }
+
+ /**
+ * Answers a CollationKey for the specified String for this Collator with
+ * the current decomposition rule and stength value.
+ *
+ * @param string
+ * the collation key.
+ * @return a CollationKey
+ */
+ public abstract CollationKey getCollationKey(String string);
+
+ /**
+ * Answers the decomposition rule for this Collator.
+ *
+ * @return the decomposition rule, either NO_DECOMPOSITION,
+ * CANONICAL_DECOMPOSITION or FULL_DECOMPOSITION
+ */
+ public int getDecomposition() {
+ return decompositionMode_ICU_Java(this.icuColl.getDecomposition());
+ }
+
+ /**
+ * Answers a Collator instance which is appropriate for the default Locale.
+ *
+ * @return a Collator
+ */
+ public static Collator getInstance() {
+ return getInstance(Locale.getDefault());
+ }
+
+ /**
+ * Answers a Collator instance which is appropriate for the specified
+ * Locale.
+ *
+ * @param locale
+ * the Locale
+ * @return a Collator
+ */
+ public static Collator getInstance(Locale locale) {
+ String key = locale.toString();
+ for (int i = cache.size() - 1; i >= 0; i -= 2) {
+ if (cache.elementAt(i).equals(key))
+ return (Collator) ((Collator) cache.elementAt(i - 1)).clone();
+ }
+
+ return new RuleBasedCollator(com.ibm.icu.text.Collator
+ .getInstance(locale));
+ }
+
+ /**
+ * Answers the strength value for this Collator.
+ *
+ * @return the strength value, either PRIMARY, SECONDARY, TERTIARY, or
+ * IDENTICAL
+ */
+ public int getStrength() {
+ return strength_ICU_Java(this.icuColl.getStrength());
+ }
+
+ /**
+ * Answers an integer hash code for the receiver. Objects which are equal
+ * answer the same value for this method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals(Object)
+ * @see #equals(String, String)
+ */
+ public abstract int hashCode();
+
+ /**
+ * Sets the decomposition rule for this Collator.
+ *
+ * @param value
+ * the decomposition rule, either NO_DECOMPOSITION,
+ * CANONICAL_DECOMPOSITION or FULL_DECOMPOSITION
+ *
+ * @exception IllegalArgumentException
+ * when the decomposition rule is not valid
+ */
+ public void setDecomposition(int value) {
+ this.icuColl.setDecomposition(decompositionMode_Java_ICU(value));
+ }
+
+ /**
+ * Sets the strength value for this Collator.
+ *
+ * @param value
+ * the strength value, either PRIMARY, SECONDARY, TERTIARY, or
+ * IDENTICAL
+ *
+ * @exception IllegalArgumentException
+ * when the strength value is not valid
+ */
+ public void setStrength(int value) {
+ this.icuColl.setStrength(strength_Java_ICU(value));
+ }
+
+ private int decompositionMode_Java_ICU(int mode) {
+ int icuDecomp = mode;
+ switch (mode) {
+ case Collator.CANONICAL_DECOMPOSITION:
+ icuDecomp = com.ibm.icu.text.Collator.CANONICAL_DECOMPOSITION;
+ break;
+ case Collator.NO_DECOMPOSITION:
+ icuDecomp = com.ibm.icu.text.Collator.NO_DECOMPOSITION;
+ break;
+ }
+ return icuDecomp;
+ }
+
+ private int decompositionMode_ICU_Java(int mode) {
+ int javaMode = mode;
+ switch (mode) {
+ case com.ibm.icu.text.Collator.NO_DECOMPOSITION:
+ javaMode = Collator.NO_DECOMPOSITION;
+ break;
+ case com.ibm.icu.text.Collator.CANONICAL_DECOMPOSITION:
+ javaMode = Collator.CANONICAL_DECOMPOSITION;
+ break;
+ }
+ return javaMode;
+ }
+
+ private int strength_Java_ICU(int value) {
+ int icuValue = value;
+ switch (value) {
+ case Collator.PRIMARY:
+ icuValue = com.ibm.icu.text.Collator.PRIMARY;
+ break;
+ case Collator.SECONDARY:
+ icuValue = com.ibm.icu.text.Collator.SECONDARY;
+ break;
+ case Collator.TERTIARY:
+ icuValue = com.ibm.icu.text.Collator.TERTIARY;
+ break;
+ case Collator.IDENTICAL:
+ icuValue = com.ibm.icu.text.Collator.IDENTICAL;
+ break;
+ }
+ return icuValue;
+
+ }
+
+ private int strength_ICU_Java(int value) {
+ int javaValue = value;
+ switch (value) {
+ case com.ibm.icu.text.Collator.PRIMARY:
+ javaValue = Collator.PRIMARY;
+ break;
+ case com.ibm.icu.text.Collator.SECONDARY:
+ javaValue = Collator.SECONDARY;
+ break;
+ case com.ibm.icu.text.Collator.TERTIARY:
+ javaValue = Collator.TERTIARY;
+ break;
+ case com.ibm.icu.text.Collator.IDENTICAL:
+ javaValue = Collator.IDENTICAL;
+ break;
+ }
+ return javaValue;
+ }
+}