001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Evgeniya G. Maenkova
019: * @version $Revision$
020: */package org.apache.harmony.awt.text;
021:
022: import java.awt.Component;
023: import java.awt.Point;
024: import java.awt.Rectangle;
025: import java.awt.font.TextHitInfo;
026: import java.awt.im.InputMethodRequests;
027: import java.text.AttributedCharacterIterator;
028: import java.text.AttributedString;
029: import java.util.Enumeration;
030: import java.util.HashSet;
031: import java.util.Map;
032: import java.util.Set;
033: import javax.swing.text.AttributeSet;
034: import javax.swing.text.BadLocationException;
035: import javax.swing.text.Document;
036: import javax.swing.text.Element;
037: import javax.swing.text.Position;
038:
039: import org.apache.harmony.awt.internal.nls.Messages;
040:
041: public class InputMethodRequestsImpl implements InputMethodRequests {
042: private TextKit textKit;
043:
044: public InputMethodRequestsImpl(final TextKit textKit) {
045: this .textKit = textKit;
046: }
047:
048: /**
049: * Uses by getCommittedText. Joins two iterators. Supposes
050: * that iterators ranges doesn't crpss.
051: */
052: final class IteratorConcatination implements
053: AttributedCharacterIterator {
054: AttributedCharacterIterator iterator = null;
055: AttributedCharacterIterator first;
056: AttributedCharacterIterator second;
057: int start;
058: int end;
059: int gapStart;
060: int gapEnd;
061: int index;
062: private static final boolean FORWARD = true;
063: private static final boolean BACKWARD = false;
064:
065: public IteratorConcatination(
066: final AttributedCharacterIterator iterator1,
067: final AttributedCharacterIterator iterator2) {
068: int begin1 = iterator1.getBeginIndex();
069: int begin2 = iterator2.getBeginIndex();
070: int end1 = iterator1.getEndIndex();
071: int end2 = iterator2.getEndIndex();
072: iterator = (begin1 < begin2) ? iterator1 : iterator2;
073: first = (begin1 < begin2) ? iterator1 : iterator2;
074: second = (begin1 < begin2) ? iterator2 : iterator1;
075: start = Math.min(begin1, begin2);
076: end = Math.max(end1, end2);
077: gapStart = Math.min(end1, end2);
078: gapEnd = Math.max(begin1, begin2);
079: index = start;
080:
081: }
082:
083: public char current() {
084: return iterator.current();
085: }
086:
087: public char first() {
088: return changeIndex(start);
089: }
090:
091: @Override
092: public Object clone() {
093: try {
094: IteratorConcatination newIterator = (IteratorConcatination) super
095: .clone();
096: return newIterator;
097: } catch (final CloneNotSupportedException e) {
098: return null;
099: }
100: }
101:
102: public Set<Attribute> getAllAttributeKeys() {
103: HashSet<Attribute> attributeKeys = new HashSet<Attribute>(
104: first.getAllAttributeKeys());
105: attributeKeys.addAll(second.getAllAttributeKeys());
106: return attributeKeys;
107: }
108:
109: public Object getAttribute(final Attribute attribute) {
110: return iterator.getAttribute(attribute);
111: }
112:
113: public Map<Attribute, Object> getAttributes() {
114: return iterator.getAttributes();
115: }
116:
117: public int getBeginIndex() {
118: return first.getBeginIndex();
119: }
120:
121: public int getEndIndex() {
122: return second.getEndIndex();
123: }
124:
125: public int getIndex() {
126: return iterator.getIndex();
127: }
128:
129: public int getRunLimit() {
130: return iterator.getRunLimit();
131: }
132:
133: public int getRunLimit(final Attribute attribute) {
134: return iterator.getRunLimit(attribute);
135: }
136:
137: public int getRunLimit(final Set<? extends Attribute> set) {
138: return iterator.getRunLimit(set);
139: }
140:
141: public int getRunStart() {
142: return iterator.getRunStart();
143: }
144:
145: public int getRunStart(final Attribute attribute) {
146: return iterator.getRunStart(attribute);
147: }
148:
149: public int getRunStart(final Set<? extends Attribute> set) {
150: return iterator.getRunStart(set);
151: }
152:
153: public char last() {
154: return changeIndex(end);
155: }
156:
157: public char next() {
158: return index < end ? changeIndex(index + 1, FORWARD) : DONE;
159: }
160:
161: public char previous() {
162: return index > start ? changeIndex(index - 1, BACKWARD)
163: : DONE;
164: }
165:
166: public char setIndex(final int ind) {
167: if (!inRange(ind)) {
168: // awt.28=bad index: {0}
169: throw new IllegalArgumentException(Messages.getString(
170: "awt.28", ind)); //$NON-NLS-1$
171: }
172: return changeIndex(ind, BACKWARD);
173: }
174:
175: boolean inGap(final int offset) {
176: return (offset >= gapStart && offset < gapEnd);
177: }
178:
179: boolean inRange(final int offset) {
180: return (offset >= start && offset < end);
181: }
182:
183: char changeIndex(final int newIndex) {
184: return changeIndex(newIndex, FORWARD);
185: }
186:
187: char changeIndex(final AttributedCharacterIterator iter,
188: final int ind) {
189: iterator = iter;
190: index = ind;
191: return iterator.setIndex(ind);
192: }
193:
194: char changeIndex(final int newIndex, final boolean direction) {
195: if (inGap(newIndex)) {
196: return (direction) ? changeIndex(second, gapEnd)
197: : changeIndex(first, gapStart - 1);
198: }
199: return newIndex < gapStart ? changeIndex(first, newIndex)
200: : changeIndex(second, newIndex);
201: }
202: }
203:
204: public AttributedCharacterIterator cancelLatestCommittedText(
205: final AttributedCharacterIterator.Attribute[] attributes) {
206:
207: ComposedTextParams composedTextParams = getComposedTextParams();
208: int lastCommittedTextLength = composedTextParams
209: .getLastCommittedTextLength();
210: int lastCommittedTextStart = composedTextParams
211: .getLastCommittedTextStart();
212: if (lastCommittedTextLength == 0) {
213: return null;
214: }
215:
216: String committedText;
217: try {
218: committedText = getText(lastCommittedTextStart,
219: lastCommittedTextLength);
220: textKit.getDocument().remove(lastCommittedTextStart,
221: lastCommittedTextLength);
222: } catch (BadLocationException e) {
223: return null;
224: }
225: return getSimpleIterator(committedText);
226: }
227:
228: public AttributedCharacterIterator getCommittedText(
229: final int beginIndex, final int endIndex,
230: final AttributedCharacterIterator.Attribute[] attributes) {
231: if (beginIndex < 0 || endIndex < beginIndex
232: || endIndex > textKit.getDocument().getLength()) {
233: // awt.29=Invalid range
234: throw new IllegalArgumentException(Messages
235: .getString("awt.29")); //$NON-NLS-1$
236: }
237: AttributedCharacterIterator result = null;
238: ComposedTextParams composedTextParams = getComposedTextParams();
239: int lastInsertPosition = composedTextParams
240: .getComposedTextStart();
241: int composedTextLength = composedTextParams
242: .getComposedTextLength();
243: try {
244: int composedTextEnd = lastInsertPosition
245: + composedTextLength;
246: int start = Math.min(lastInsertPosition, beginIndex);
247: int end = Math.min(endIndex, lastInsertPosition);
248: String textBefore = getText(start, end - start);
249: String textAfter = null;
250: end = endIndex + composedTextLength;
251: if (composedTextEnd < endIndex + composedTextLength) {
252: start = composedTextEnd;
253: textAfter = getText(start, end - start);
254: }
255: result = getSimpleIterator(textBefore, textAfter);
256: } catch (BadLocationException e) {
257: }
258: return result;
259: }
260:
261: public int getCommittedTextLength() {
262: return textKit.getDocument().getLength()
263: - getComposedTextParams().getComposedTextLength();
264: }
265:
266: public int getInsertPositionOffset() {
267: return getComposedTextParams().getComposedTextStart();
268: }
269:
270: public TextHitInfo getLocationOffset(final int x, final int y) {
271: Point p = new Point(x, y);
272: final Component component = textKit.getComponent();
273: if (!component.isDisplayable()) {
274: return null;
275: }
276: Point location = component.getLocationOnScreen();
277: p.translate(-location.x, -location.y);
278: if (!component.contains(p)) {
279: // Return null if the location is outside the component.
280: return null;
281: }
282: int offset = textKit.viewToModel(p, new Position.Bias[1]);
283: ComposedTextParams composedTextParams = getComposedTextParams();
284: int lastInsertPosition = composedTextParams
285: .getComposedTextStart();
286: int composedTextLength = composedTextParams
287: .getComposedTextLength();
288: if (composedTextLength == 0) {
289: return null;
290: } else if (offset >= lastInsertPosition
291: && offset <= lastInsertPosition + composedTextLength) {
292: return TextHitInfo.afterOffset(offset - lastInsertPosition);
293: } else {
294: return null;
295: }
296: }
297:
298: public AttributedCharacterIterator getSelectedText(
299: final AttributedCharacterIterator.Attribute[] attributes) {
300: return getSimpleIterator(textKit.getSelectedText());
301: }
302:
303: AttributedCharacterIterator getIterator(final int start,
304: final int end) {
305: AttributedString s = getAttributedString(start, end);
306: return (s == null) ? null : s.getIterator(null, start, end);
307: }
308:
309: AttributedString getAttributedString(final int start, final int end) {
310: String s = null;
311: try {
312: s = getText(0, end);
313: } catch (final BadLocationException e) {
314: }
315: if (s == null || start == end) {
316: return null;
317: }
318: AttributedString attributedString = new AttributedString(s);
319: for (int i = start; i < end; i++) {
320: AttributeSet ass = getAttributeSet(i);
321: Enumeration<?> names;
322: for (names = ass.getAttributeNames(); names
323: .hasMoreElements();) {
324: Object key = names.nextElement();
325: if (key instanceof AttributedCharacterIterator.Attribute) {
326: AttributedCharacterIterator.Attribute attribute = (AttributedCharacterIterator.Attribute) key;
327: Object value = ass.getAttribute(key);
328: attributedString.addAttribute(attribute, value, i
329: - start, i + 1 - start);
330: }
331: }
332: }
333: return attributedString;
334: }
335:
336: AttributeSet getAttributeSet(final int offset) {
337: Document doc = textKit.getDocument();
338: Element elem = getLeafElement(doc.getDefaultRootElement(),
339: offset);
340: return (elem == null) ? null : elem.getAttributes();
341: }
342:
343: Element getLeafElement(final Element element, final int offset) {
344: int count = element.getElementCount();
345: if (count == 0) {
346: return element;
347: }
348: int index = element.getElementIndex(offset);
349: return index < 0 ? element : getLeafElement(element
350: .getElement(index), offset);
351: }
352:
353: public Rectangle getTextLocation(final TextHitInfo offset) {
354: Point location = textKit.getComponent().getLocationOnScreen();
355: Rectangle rect = null;
356: try {
357: rect = textKit.modelToView(getComposedTextParams()
358: .getComposedTextStart());
359: rect.translate(location.x, location.y);
360: } catch (BadLocationException e) {
361: }
362: return rect;
363: }
364:
365: private AttributedCharacterIterator getSimpleIterator(
366: final String text) {
367: return (text == null) ? null : new AttributedString(text)
368: .getIterator();
369: }
370:
371: private AttributedCharacterIterator getSimpleIterator(
372: final String text1, final String text2) {
373: if (text1 == null) {
374: return getSimpleIterator(text2);
375: } else if (text2 == null) {
376: return getSimpleIterator(text1);
377: } else {
378: return getSimpleIterator(text1 + text2);
379: }
380: }
381:
382: private ComposedTextParams getComposedTextParams() {
383: return TextUtils.getComposedTextParams(textKit);
384: }
385:
386: private String getText(final int pos, final int length)
387: throws BadLocationException {
388: return textKit.getDocument().getText(pos, length);
389: }
390: }
|