FileDocCategorySizeDatePackage
CityInputMethod.javaAPI DocExample27286Wed Apr 19 11:19:40 BST 2000com.sun.demos.cityim.internal

CityInputMethod

public class CityInputMethod extends Object implements InputMethod

Fields Summary
private static Locale
YOMI
private static Locale[]
SUPPORTED_LOCALES
private static Locale[]
LOOKUP_LOCALES
private static Properties
cityNames
private static Properties
cityAliases
private static Properties
cityLanguages
private static Properties
templates
private static Window
statusWindow
private static CityInputMethod
statusWindowOwner
private static boolean
attachedStatusWindow
private Rectangle
clientWindowLocation
private static Point
globalStatusWindowLocation
private static HashSet
cityInputMethodInstances
private String[]
lookupCandidates
private Locale[]
lookupLocales
private int
lookupCandidateCount
private LookupList
lookupList
private int
lookupSelection
InputMethodContext
inputMethodContext
private boolean
active
private boolean
disposed
private Locale
locale
private boolean
converted
private StringBuffer
rawText
private String
convertedText
private int
insertionPoint
private String[]
rawTextSegs
private String[]
convertedSegs
private String
fmt
private int[]
fieldPos
private int[]
segPos
private int
selectedSeg
private int
numSegs
private int
committedSeg
private int
previouslyCommittedCharacterCount
Constructors Summary
public CityInputMethod()


        
        initializeTables();
        rawText = new StringBuffer();
    
Methods Summary
public voidactivate()

        if (active) {
            System.out.println("CityInputMethod.activate called while active");
        }
        active = true;
	synchronized (statusWindow) {
	    statusWindowOwner = this; 
	    updateStatusWindow(locale);
	    if (!statusWindow.isVisible()) {
		statusWindow.setVisible(true);
	    }
	    setStatusWindowForeground(Color.black);
	}
    
voidcloseLookupWindow()

        if (lookupList != null) {
            lookupList.setVisible(false);
            lookupList = null;
        }
    
private voidcommit(int index)

	if (index >= (numSegs - 1)) {
	    // if this is the last segment, commit all
	    commitAll();
	} else {
	    committedSeg = index;
	    selectedSeg = committedSeg + 1;
	    sendText(true);
	}
    
voidcommitAll()

	committedSeg = numSegs - 1;
        sendText(true);
	// once composed text is committed, reinitialize all variables
	rawText.setLength(0);
        convertedText = null;
        converted = false;

	rawTextSegs = null;
	convertedSegs = null;
	fmt = null;
	fieldPos = null;
	segPos = null;
	selectedSeg = 0;
	insertionPoint = rawText.length();
	numSegs = 0;
	committedSeg = -1;
	previouslyCommittedCharacterCount = 0;
    
voidconvertAgain()

        String lookupName;
	lookupName = rawTextSegs[selectedSeg];
	// if converted string is same as original, it's not in word list. We skip
	// further conversion.
	if (!lookupName.equals(convertedSegs[selectedSeg])) {
	    lookupName = findAlias(lookupName);
	    lookupCandidates = new String[LOOKUP_LOCALES.length];
	    lookupLocales = new Locale[LOOKUP_LOCALES.length];
	    lookupCandidateCount = 0;
	    lookupSelection = 0;
	    for (int i = 0; i < LOOKUP_LOCALES.length; i++) {
		Locale iLocale = LOOKUP_LOCALES[i];
		String localeLookupName = lookupName + '_" + iLocale;
		String localeConvertedText = (String) cityNames.get(localeLookupName);
		if (localeConvertedText != null) {
		    lookupCandidates[lookupCandidateCount] = localeConvertedText;
		    lookupLocales[lookupCandidateCount] = iLocale;
		    lookupCandidateCount++;
		} else if (iLocale.equals(Locale.ENGLISH)) {
		    localeConvertedText = (String) cityNames.get(lookupName);
		    if (localeConvertedText != null) {
			lookupCandidates[lookupCandidateCount] = localeConvertedText;
			lookupLocales[lookupCandidateCount] = iLocale;
			lookupCandidateCount++;
		    }
		}
		if (convertedSegs[selectedSeg].equals(localeConvertedText)) {
		    lookupSelection = lookupCandidateCount - 1;
		}
	    }
	    openLookupWindow();
	} else {
	    Toolkit.getDefaultToolkit().beep();
	}
    
voidconvertFirstTime()

	numSegs = rawText.length() / 3;
	rawTextSegs = new String[numSegs];
	convertedSegs = new String[numSegs];
	for (int i = 0; i < numSegs; ++i) {
	    rawTextSegs[i] = rawText.substring(i * 3, (i + 1) *3);
	    String alias = findAlias(rawTextSegs[i]);
	    String result = lookup(alias, cityNames);
	    if (result != null) {
		convertedSegs[i] = result;
	    } else {
		convertedSegs[i] = rawText.substring(i * 3, (i + 1) * 3);
	    }
	}
	converted = true;
	sendText(false);
    
public voiddeactivate(boolean isTemporary)

        closeLookupWindow();
        if (!active) {
            System.out.println("CityInputMethod.deactivate called while not active");
        }
	setStatusWindowForeground(Color.lightGray);
        active = false;
    
public voiddispatchEvent(java.awt.AWTEvent event)

        if (!active && (event instanceof KeyEvent)) {
            System.out.println("CityInputMethod.dispatch called with KeyEvent while not active");
        }
        if (disposed) {
            System.out.println("CityInputMethod.dispatch called after being disposed");
        }
        if (!(event instanceof InputEvent)) {
            System.out.println("CityInputMethod.dispatch called with event that's not an InputEvent");
        }
	if (event.getID() == KeyEvent.KEY_RELEASED) {
	    if (lookupList != null) { // if candidate window is active
		KeyEvent e = (KeyEvent) event;
		if (e.isControlDown()) {
		    if (e.getKeyCode() == KeyEvent.VK_DOWN) {
		        // Control + Arrow Down commits chunks
			closeLookupWindow();
			commit(selectedSeg);
			e.consume();
		    }
		} else {
		    // select candidate by Arrow Up/Down
		    if (e.getKeyCode() == KeyEvent.VK_DOWN) {
			if (++lookupSelection == lookupCandidateCount) {
			    lookupSelection = 0;
			}
			selectCandidate(lookupSelection);
			e.consume();
		    } else if (e.getKeyCode() == KeyEvent.VK_UP) {
			if (--lookupSelection < 0) {
			    lookupSelection = lookupCandidateCount;
			}
			selectCandidate(lookupSelection);
			e.consume();
		    }
		}
	    } else {
		if (event.getID() == KeyEvent.KEY_RELEASED) {
		    KeyEvent e = (KeyEvent) event;
		    if (e.isControlDown()) {
			if (e.getKeyCode() == KeyEvent.VK_DOWN) {
			    // Control + Arrow Down commits chunks
			    commit(selectedSeg);
			    e.consume();
			}
		    } else {
		        // move selected segment by Arrow Right/Left
			if ((e.getKeyCode() == KeyEvent.VK_RIGHT) && (converted == true)) {
			    if (selectedSeg < (numSegs - 1)) {
				selectedSeg++;
				sendText(false);
				e.consume();
			    } else {
				Toolkit.getDefaultToolkit().beep();
			    }
			} else if ((e.getKeyCode() == KeyEvent.VK_LEFT) && (converted == true)) {
			    if (selectedSeg > (committedSeg + 1)) {
				selectedSeg--;
				sendText(false);
				e.consume();
			    } else {
				Toolkit.getDefaultToolkit().beep();
			    }
			}
		    }
		}
	    }
	}
	if (event.getID() == MouseEvent.MOUSE_CLICKED) {
	    MouseEvent e = (MouseEvent) event;
	    Component comp = e.getComponent();
	    Point pnt = comp.getLocationOnScreen();
	    int x = (int)pnt.getX() + e.getX();
	    int y = (int)pnt.getY() + e.getY();
	    TextHitInfo hit = inputMethodContext.getLocationOffset(x,y);
	    if (hit != null) {
	        // within composed text
		if (converted) {
		    selectedSeg = findSegment(hit.getInsertionIndex());
		    sendText(false);
		    e.consume();
		} else {
		    insertionPoint = hit.getInsertionIndex();
		}
	    } else {
	        // if hit outside composition, simply commit all.
		commitAll();
	    }
	}
        if (event.getID() == KeyEvent.KEY_TYPED) {
            KeyEvent e = (KeyEvent) event;
            if (handleCharacter(e.getKeyChar())) {
                e.consume();
            }
        }
    
public voiddispose()

        if (active) {
            System.out.println("CityInputMethod.dispose called while active");
        }
        if (disposed) {
            System.out.println("CityInputMethod.disposed called repeatedly");
        }
        closeLookupWindow();
	synchronized (statusWindow) {
	    cityInputMethodInstances.remove(this);
	}
        disposed = true;
    
public voidendComposition()

        if (rawText.length() != 0) {
            commitAll();
        }
        closeLookupWindow();
    
java.lang.StringfindAlias(java.lang.String lookupName)

        lookupName = lookupName.toUpperCase();
	return cityAliases.getProperty(lookupName, lookupName);
    
intfindSegment(int insertion)
find segment at insertion point

	for (int i = committedSeg + 1; i < numSegs; i++) {
	    if ((segPos[i][0] < insertion) && (insertion < segPos[i][1])) {
		return i;
	    }
	}
	return 0;
    
voidformatOutput()

	if (fmt == null) {
	    String key = "Template" + Integer.toString(numSegs);
	    fmt = lookup(key, templates);
	    parseFormat();
	}
	convertedText = MessageFormat.format(fmt, (Object [])convertedSegs);
	// Figure out converted segment position
	int errors = 0;
	segPos = new int[fieldPos.length][2];
	for (int i = 0; i < fieldPos.length; i++) {
	    int optLen = (fieldPos[i][1] - fieldPos[i][0]) + 1;
	    int diffs = convertedSegs[i].length() - optLen;
	    segPos[i][0] = fieldPos[i][0] + errors;
	    segPos[i][1] = segPos[i][0] + convertedSegs[i].length();
	    errors += diffs;
	}
    
public java.lang.ObjectgetControlObject()

        return null;
    
public java.util.LocalegetLocale()

        return locale;
    
intgetSelectedSegmentOffset()

        return segPos[selectedSeg][0] - previouslyCommittedCharacterCount;
    
private booleanhandleCharacter(char ch)
Attempts to handle a typed character.

return
whether the character was handled

        if (lookupList != null) {
            if (ch == ' ") {
                if (++lookupSelection == lookupCandidateCount) {
                    lookupSelection = 0;
                }
                selectCandidate(lookupSelection);
                return true;
            } else if (ch == '\n") {
                commitAll();
                closeLookupWindow();
                return true;
            } else if ('1" <= ch && ch <= '0" + lookupCandidateCount) {
                selectCandidate(ch - '1");
                closeLookupWindow();
                return true;
            } else {
                Toolkit.getDefaultToolkit().beep();
                return true;
            }
        } else if (converted) {
            if (ch == ' ") {
                convertAgain();
                return true;
            } else if (ch == '\n") {
                commitAll();
                return true;
            } else {
                Toolkit.getDefaultToolkit().beep();
                return true;
            }
        } else {
            if (ch == ' ") {
                int length = rawText.length();
                if (length == 3 || length == 6 || length == 9) {
                    convertFirstTime();
                    return true;
                }
            } else if (ch == '\n") {
                if (rawText.length() != 0) {
                    commitAll();
                    return true;
                }
            } else if (ch == '\b") {
                if (insertionPoint > 0) {
		    rawText.deleteCharAt(insertionPoint - 1);
		    --insertionPoint;
                    sendText(false);
                    return true;
                }
            } else if ('a" <= ch && ch <= 'z" || 'A" <= ch && ch <= 'Z") {
		rawText.insert(insertionPoint++, ch);
                sendText(false);
                return true;
            }
            if (rawText.length() != 0) {
                Toolkit.getDefaultToolkit().beep();
                return true;
            }
        }
        return false;
    
public voidhideWindows()

        if (active) {
            System.out.println("CityInputMethod.hideWindows called while active");
        }
        closeLookupWindow();
	synchronized (statusWindow) {
	    if (statusWindowOwner == this) {
		statusWindow.setVisible(false);
	    }
	}
    
private voidinitializeTables()

        synchronized (this.getClass()) {
            if (templates == null) {
                cityNames = loadProperties("names.properties");
                cityAliases = loadProperties("aliases.properties");
                cityLanguages = loadProperties("languages.properties");
                templates = loadProperties("templates.properties");
            }
        }
    
public booleanisCompositionEnabled()

        // always enabled
	return true;
    
private java.util.PropertiesloadProperties(java.lang.String fileName)

        Properties props = new Properties();
        InputStream stream = this.getClass().getResourceAsStream(fileName);
        props.load(stream);
        stream.close();
        return props;
    
java.lang.Stringlookup(java.lang.String lookupName, java.util.Properties table)

	String result = null;
        String localeLookupName = lookupName + "_" + locale;
        while (true) {
            result = (String) table.get(localeLookupName);
            if (result != null) {
                break;
            }
            int index = localeLookupName.lastIndexOf("_");
            if (index == -1) {
                break;
            }
            localeLookupName = localeLookupName.substring(0, index);
        }
	return result;
    
public voidnotifyClientWindowChange(java.awt.Rectangle location)

	clientWindowLocation = location;
	synchronized (statusWindow) {
	    if (!attachedStatusWindow || statusWindowOwner != this) {
		return;
	    }
	    if (location != null) {
		statusWindow.setLocation(location.x, location.y+location.height);
		if (!statusWindow.isVisible()) {
		    if (active) {
			setStatusWindowForeground(Color.black);
		    } else {
			setStatusWindowForeground(Color.lightGray);
		    }
		    statusWindow.setVisible(true);
		}
	    } else {
		statusWindow.setVisible(false);
	    }
	}
    
voidopenLookupWindow()

        lookupList = new LookupList(this, inputMethodContext, 
				    lookupCandidates, lookupLocales, lookupCandidateCount);
        lookupList.selectCandidate(lookupSelection);
    
voidparseFormat()

	Vector vec = new Vector();
	int[] elem = null;

	for(int i = 0; i < fmt.length(); i++) {
	    if (fmt.charAt(i) == '{") {
		elem = new int[2];
		elem[0] = i;
	    } else if (fmt.charAt(i) == '}") {
		elem[1] = i;
		vec.add(elem);
	    }
	}
	if (vec.size() != 0) {
	    fieldPos = new int[vec.size()][];
	    vec.toArray(fieldPos);
	}
    
public voidreconvert()

	// not supported yet
	throw new UnsupportedOperationException();
    
public voidremoveNotify()

    
voidselectCandidate(int candidate)

        lookupSelection = candidate;
        lookupList.selectCandidate(lookupSelection);
        convertedSegs[selectedSeg] = lookupCandidates[lookupSelection];
        sendText(false);
    
voidsendText(boolean committed)

	AttributedString as = null;
	TextHitInfo caret = null;
	int committedCharacterCount = 0;
	int newTotalCommittedCharacterCount = previouslyCommittedCharacterCount;

	if (converted) {
	    formatOutput();
	    if (committed) {
		if (committedSeg == (numSegs - 1)) {
		    newTotalCommittedCharacterCount = convertedText.length();
		} else {
		    newTotalCommittedCharacterCount = segPos[committedSeg + 1][0];
		}
		committedCharacterCount = newTotalCommittedCharacterCount - previouslyCommittedCharacterCount;
	    }
            as = new AttributedString(convertedText.substring(previouslyCommittedCharacterCount));
            for(int i = committedSeg + 1; i < numSegs; i++) {
                InputMethodHighlight highlight;
                if (i == selectedSeg) {
                    highlight = InputMethodHighlight.SELECTED_CONVERTED_TEXT_HIGHLIGHT;
                } else {
                    highlight = InputMethodHighlight.UNSELECTED_CONVERTED_TEXT_HIGHLIGHT;
                }
                as.addAttribute(TextAttribute.INPUT_METHOD_HIGHLIGHT, highlight,
                                segPos[i][0] - previouslyCommittedCharacterCount,
                                segPos[i][1] - previouslyCommittedCharacterCount);
            }
            previouslyCommittedCharacterCount = newTotalCommittedCharacterCount;
	} else {
	    as = new AttributedString(rawText.toString());
	    if (committed) {
	        committedCharacterCount = rawText.length();
	    } else if (rawText.length() != 0) {
		as.addAttribute(TextAttribute.INPUT_METHOD_HIGHLIGHT,
				InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT);
	        caret = TextHitInfo.leading(insertionPoint);
	    }
	}
	inputMethodContext.dispatchInputMethodEvent(
						    InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
						    as.getIterator(),
						    committedCharacterCount,
						    caret,
						    null);
    
public voidsetCharacterSubsets(java.lang.Character$Subset[] subsets)

        // ignore
    
public voidsetCompositionEnabled(boolean enable)

	// not supported yet
	throw new UnsupportedOperationException();
    
public voidsetInputMethodContext(java.awt.im.spi.InputMethodContext context)

        inputMethodContext = context;
	if (statusWindow == null) {
            Window sw = context.createInputMethodWindow("City Input Method", false);
	    Label label = new Label();
	    label.setForeground(Color.black);
	    label.setBackground(Color.white);
	    synchronized (this.getClass()) {
		if (statusWindow == null) {
		    statusWindow = sw;
		    statusWindow.addComponentListener(new ComponentListener() {
			public void componentResized(ComponentEvent e) {}
			public void componentMoved(ComponentEvent e) {
			    synchronized (statusWindow) {
				if (!attachedStatusWindow) {
				    Component comp = e.getComponent();
				    if (comp.isVisible()) {
					globalStatusWindowLocation = comp.getLocation();
				    }
				}
			    }
			}
			public void componentShown(ComponentEvent e) {}
			public void componentHidden(ComponentEvent e) {}
		    });
		    label.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
			    int count = e.getClickCount();
			    if (count >= 2) {
				toggleStatusWindowStyle();
			    }
			}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
		    });
		    statusWindow.add(label);
		    statusWindowOwner = this;
		    updateStatusWindow(locale);
		    label.setSize(200, 50);
		    statusWindow.pack();
		}
	    }
	}
	inputMethodContext.enableClientWindowNotification(this, attachedStatusWindow);
	synchronized (statusWindow) {
	    cityInputMethodInstances.add(this);
	}
    
public booleansetLocale(java.util.Locale locale)

        for (int i = 0; i < SUPPORTED_LOCALES.length; i++) {
            if (locale.equals(SUPPORTED_LOCALES[i])) {
                this.locale = locale;
		if (statusWindow != null) {
		    updateStatusWindow(locale);
		}
                return true;
            }
        }
        return false;
    
private voidsetPCStyleStatusWindow()

	synchronized (statusWindow) {
	    if (globalStatusWindowLocation == null) {
		Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
		globalStatusWindowLocation = new Point(d.width - statusWindow.getWidth(),
						       d.height - statusWindow.getHeight() - 25);
	    }
	    statusWindow.setLocation(globalStatusWindowLocation.x, globalStatusWindowLocation.y);
	}
    
private voidsetStatusWindowForeground(java.awt.Color fg)

	synchronized (statusWindow) {
	    if (statusWindowOwner != this) {
		return;
	    }
	    Label label = (Label) statusWindow.getComponent(0);
	    label.setForeground(fg);
	}
    
private voidtoggleStatusWindowStyle()

	synchronized (statusWindow) {
	    if (attachedStatusWindow) {
		attachedStatusWindow = false;
		setPCStyleStatusWindow();
	    } else {
		attachedStatusWindow = true;
	    }
	    Iterator itr = cityInputMethodInstances.iterator();
	    while (itr.hasNext()) {
		CityInputMethod im = (CityInputMethod)itr.next();
		im.inputMethodContext.enableClientWindowNotification(im, attachedStatusWindow);
	    }
	}
    
voidupdateStatusWindow(java.util.Locale locale)

	synchronized (statusWindow) {
	    Label label = (Label) statusWindow.getComponent(0);
	    String localeName = locale == null ? "null" : locale.getDisplayName();
	    String text = "Current locale: " + localeName;
	    if (!label.getText().equals(text)) {
		label.setText(text);
		statusWindow.pack();
	    }
	    if (attachedStatusWindow) {
		if (clientWindowLocation != null) {
		    statusWindow.setLocation(clientWindowLocation.x,
					     clientWindowLocation.y + clientWindowLocation.height);
		}
	    } else {
		setPCStyleStatusWindow();
	    }
	}