blob: 02bcd5996a5607a8389eab3e600cd67457e7bc7a [file] [log] [blame]
package com.ibm.text.components;
import java.awt.*;
import java.awt.event.*;
import java.text.*;
import java.awt.datatransfer.*;
import com.ibm.text.*;
/**
* A subclass of {@link DumbTextComponent} that passes key events through
* a {@link com.ibm.text.Transliterator}.
*
* <p>Copyright &copy; IBM Corporation 1999. All rights reserved.
*
* @author Alan Liu
* @version $RCSfile: TransliteratingTextComponent.java,v $ $Revision: 1.1 $ $Date: 1999/12/20 18:29:21 $
*/
public class TransliteratingTextComponent extends DumbTextComponent {
private static boolean DEBUG = false;
private Transliterator translit = null;
// Index into getText() where the start of transliteration is.
// As we commit text during keyboardTransliteration, we advance
// this.
private int start = 0;
// Index into getText() where the cursor is; cursor >= start
private int cursor = 0;
private static final String COPYRIGHT =
"\u00A9 IBM Corporation 1999. All rights reserved.";
/**
* Constructor.
*/
public TransliteratingTextComponent() {
super();
addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// We get an ActionEvent only when the selection changes
resetTransliterationStart();
}
});
}
/**
* {@link DumbTextComponent} API. Framework method that is called
* when a <code>KeyEvent</code> is received. This implementation
* runs the new character through the current
* <code>Transliterator</code>, if one is set, and inserts the
* transliterated text into the buffer.
*/
protected void handleKeyTyped(KeyEvent e) {
char ch = e.getKeyChar();
if (translit == null) {
super.handleKeyTyped(e);
return;
}
// ------------------------------------------------------------
// The following case motivates the two lines that recompute
// start and cursor below.
// " "
// a b c q r|s t u m m
// 0 1 2 3 4 5 6 7 8 9
// 0 1 2
// start 3, cursor 5, sel 6 -> { 0, 3, 2 }
// : new int[] { 0, sel - start, cursor - start };
// sz>99|9
// " { "
// a b c q r 9 9|9 t u m m
// 0 1 2 3 4 5 6 7 8 9 a b
// 0 1 2 3 4
// { 3, 5, 4 } -> start 6, cursor 7, sel 8
// : start += index[0];
// : cursor = start + index[2] - index[0];
// ------------------------------------------------------------
// Need to save start because calls to replaceRange will update
// start and cursor.
int saveStart = start;
ReplaceableString buf = new ReplaceableString();
buf.getStringBuffer().append(getText().substring(start,
getSelectionStart()));
int[] index = new int[] { 0, getSelectionStart() - start,
cursor - start};
StringBuffer log = null;
if (DEBUG) {
log = new StringBuffer();
log.append("start " + start + ", cursor " + cursor);
log.append(", sel " + getSelectionStart());
log.append(", {" + index[0] + ", " + index[1] + ", " + index[2] + "}, ");
log.append('"' + buf.toString() + "\" + '" + ch + "' -> \"");
}
translit.keyboardTransliterate(buf, index, ch);
replaceRange(buf.toString(), start, getSelectionEnd());
// At this point start has been changed by the callback to
// resetTransliteratorStart() via replaceRange() -- so use our
// local copy, saveStart.
// The START index is zero-based. On entry to keyboardTransliterate(),
// it was zero. We can therefore just add it to our original
// getText()-based index value of start (in saveStart) to get
// the new getText()-based start.
start = saveStart + index[Transliterator.START];
// Make the cursor getText()-based. The CURSOR index is zero-based.
cursor = start + index[Transliterator.CURSOR]
- index[Transliterator.START];
if (DEBUG) {
String out = buf.toString();
log.append(out.substring(0, index[Transliterator.START])).
append('{').
append(out.substring(index[Transliterator.START],
index[Transliterator.CURSOR])).
append('|').
append(out.substring(index[Transliterator.CURSOR])).
append('"');
log.append(", {" + index[0] + ", " + index[1] + ", " + index[2] + "}, ");
log.append("start " + start + ", cursor " + cursor);
log.append(", sel " + getSelectionStart());
System.out.println(escape(log.toString()));
}
}
/**
* Set the {@link com.ibm.text.Transliterator} and direction to
* use to process incoming <code>KeyEvent</code>s.
* @param t the {@link com.ibm.text.Transliterator} to use
*/
public void setTransliterator(Transliterator t) {
if (translit != t) { // [sic] pointer compare ok; singletons
resetTransliterationStart();
}
translit = t;
}
/**
* Reset the start point at which transliteration begins. This
* needs to be done when the user moves the cursor or when the
* current {@link com.ibm.text.Transliterator} is changed.
*/
private void resetTransliterationStart() {
start = getSelectionStart();
cursor = start;
}
/**
* Escape non-ASCII characters as Unicode.
* JUST FOR DEBUGGING OUTPUT.
*/
public static final String escape(String s) {
StringBuffer buf = new StringBuffer();
for (int i=0; i<s.length(); ++i) {
char c = s.charAt(i);
if (c >= ' ' && c <= 0x007F) {
if (c == '\\') {
buf.append("\\\\"); // That is, "\\"
} else {
buf.append(c);
}
} else {
buf.append("\\u");
if (c < 0x1000) {
buf.append('0');
if (c < 0x100) {
buf.append('0');
if (c < 0x10) {
buf.append('0');
}
}
}
buf.append(Integer.toHexString(c));
}
}
return buf.toString();
}
}