351 lines · 12.2 KB · Java
RawDownload
/* * Copyright (c) 1999, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.awt.im; import java.awt.Component;import java.awt.Container;import java.awt.Rectangle;import java.awt.event.InputMethodEvent;import java.awt.event.InputMethodListener;import java.awt.font.TextAttribute;import java.awt.font.TextHitInfo;import java.awt.im.InputMethodRequests;import java.text.AttributedCharacterIterator;import java.text.AttributedCharacterIterator.Attribute;import java.text.AttributedString; /** * A composition area handler handles events and input method requests for * the composition area. Typically each input method context has its own * composition area handler if it supports passive clients or below-the-spot * input, but all handlers share a single composition area. * * @author JavaSoft International */ class CompositionAreaHandler implements InputMethodListener,                                                 InputMethodRequests {     private static CompositionArea compositionArea;    private static Object compositionAreaLock = new Object();    private static CompositionAreaHandler compositionAreaOwner; // synchronized through compositionArea     private AttributedCharacterIterator composedText;    private TextHitInfo caret = null;    private Component clientComponent = null;    private InputMethodContext inputMethodContext;     /**     * Constructs the composition area handler.     */    CompositionAreaHandler(InputMethodContext context) {        inputMethodContext = context;    }     /**     * Creates the composition area.     */    private void createCompositionArea() {        synchronized(compositionAreaLock) {            compositionArea = new CompositionArea();            if (compositionAreaOwner != null) {                compositionArea.setHandlerInfo(compositionAreaOwner, inputMethodContext);            }            // If the client component is an active client using below-the-spot style, then            // make the composition window undecorated without a title bar.            if(clientComponent!=null){                InputMethodRequests req = clientComponent.getInputMethodRequests();                if (req != null && inputMethodContext.useBelowTheSpotInput()) {                    setCompositionAreaUndecorated(true);                }            }        }    }     void setClientComponent(Component clientComponent) {        this.clientComponent = clientComponent;    }     /**     * Grabs the composition area, makes this handler its owner, and installs     * the handler and its input context into the composition area for event     * and input method request handling.     * If doUpdate is true, updates the composition area with previously sent     * composed text.     */     void grabCompositionArea(boolean doUpdate) {        synchronized (compositionAreaLock) {            if (compositionAreaOwner != this) {                compositionAreaOwner = this;                if (compositionArea != null) {                    compositionArea.setHandlerInfo(this, inputMethodContext);                }                if (doUpdate) {                    // Create the composition area if necessary                    if ((composedText != null) && (compositionArea == null)) {                        createCompositionArea();                    }                    if (compositionArea != null) {                        compositionArea.setText(composedText, caret);                    }                }            }        }    }     /**     * Releases and closes the composition area if it is currently owned by     * this composition area handler.     */    void releaseCompositionArea() {        synchronized (compositionAreaLock) {            if (compositionAreaOwner == this) {                compositionAreaOwner = null;                if (compositionArea != null) {                    compositionArea.setHandlerInfo(null, null);                    compositionArea.setText(null, null);                }            }        }    }     /**     * Releases and closes the composition area if it has been created,     * independent of the current owner.     */    static void closeCompositionArea() {        if (compositionArea != null) {            synchronized (compositionAreaLock) {                compositionAreaOwner = null;                compositionArea.setHandlerInfo(null, null);                compositionArea.setText(null, null);            }        }    }     /**     * Returns whether the composition area is currently visible     */    boolean isCompositionAreaVisible() {        if (compositionArea != null) {            return compositionArea.isCompositionAreaVisible();        }         return false;    }      /**     * Shows or hides the composition Area     */    void setCompositionAreaVisible(boolean visible) {        if (compositionArea != null) {            compositionArea.setCompositionAreaVisible(visible);        }    }     void processInputMethodEvent(InputMethodEvent event) {        if (event.getID() == InputMethodEvent.INPUT_METHOD_TEXT_CHANGED) {            inputMethodTextChanged(event);        } else {            caretPositionChanged(event);        }    }     /**     * set the compositionArea frame decoration     */    void setCompositionAreaUndecorated(boolean undecorated) {        if (compositionArea != null) {            compositionArea.setCompositionAreaUndecorated(undecorated);        }    }     //    // InputMethodListener methods    //     private static final Attribute[] IM_ATTRIBUTES =            { TextAttribute.INPUT_METHOD_HIGHLIGHT };     public void inputMethodTextChanged(InputMethodEvent event) {        AttributedCharacterIterator text = event.getText();        int committedCharacterCount = event.getCommittedCharacterCount();         // extract composed text and prepare it for display        composedText = null;        caret = null;        if (text != null                && committedCharacterCount < text.getEndIndex() - text.getBeginIndex()) {             // Create the composition area if necessary            if (compositionArea == null) {                 createCompositionArea();            }             // copy the composed text            AttributedString composedTextString;            composedTextString = new AttributedString(text,                    text.getBeginIndex() + committedCharacterCount, // skip over committed text                    text.getEndIndex(), IM_ATTRIBUTES);            composedTextString.addAttribute(TextAttribute.FONT, compositionArea.getFont());            composedText = composedTextString.getIterator();            caret = event.getCaret();        }         if (compositionArea != null) {            compositionArea.setText(composedText, caret);        }         // send any committed text to the text component        if (committedCharacterCount > 0) {            inputMethodContext.dispatchCommittedText(((Component) event.getSource()),                                                     text, committedCharacterCount);             // this may have changed the text location, so reposition the window            if (isCompositionAreaVisible()) {                compositionArea.updateWindowLocation();            }        }         // event has been handled, so consume it        event.consume();    }     public void caretPositionChanged(InputMethodEvent event) {        if (compositionArea != null) {            compositionArea.setCaret(event.getCaret());        }         // event has been handled, so consume it        event.consume();    }     //    // InputMethodRequests methods    //     /**     * Returns the input method request handler of the client component.     * When using the composition window for an active client (below-the-spot     * input), input method requests that do not relate to the display of     * the composed text are forwarded to the client component.     */    InputMethodRequests getClientInputMethodRequests() {        if (clientComponent != null) {            return (InputMethodRequests) clientComponent.getInputMethodRequests();        }         return null;    }     public Rectangle getTextLocation(TextHitInfo offset) {        synchronized (compositionAreaLock) {            if (compositionAreaOwner == this && isCompositionAreaVisible()) {                return compositionArea.getTextLocation(offset);            } else if (composedText != null) {                // there's composed text, but it's not displayed, so fake a rectangle                return new Rectangle(0, 0, 0, 10);            } else {                InputMethodRequests requests = getClientInputMethodRequests();                if (requests != null) {                    return requests.getTextLocation(offset);                } else {                    // passive client, no composed text, so fake a rectangle                    return new Rectangle(0, 0, 0, 10);                }            }        }    }     public TextHitInfo getLocationOffset(int x, int y) {        synchronized (compositionAreaLock) {            if (compositionAreaOwner == this && isCompositionAreaVisible()) {                return compositionArea.getLocationOffset(x, y);            } else {                return null;            }        }    }     public int getInsertPositionOffset() {        InputMethodRequests req = getClientInputMethodRequests();        if (req != null) {            return req.getInsertPositionOffset();        }         // we don't have access to the client component's text.        return 0;    }     private static final AttributedCharacterIterator EMPTY_TEXT =            (new AttributedString("")).getIterator();     public AttributedCharacterIterator getCommittedText(int beginIndex,                                                       int endIndex,                                                       Attribute[] attributes) {        InputMethodRequests req = getClientInputMethodRequests();        if(req != null) {            return req.getCommittedText(beginIndex, endIndex, attributes);        }         // we don't have access to the client component's text.        return EMPTY_TEXT;    }     public int getCommittedTextLength() {        InputMethodRequests req = getClientInputMethodRequests();        if(req != null) {            return req.getCommittedTextLength();        }         // we don't have access to the client component's text.        return 0;    }      public AttributedCharacterIterator cancelLatestCommittedText(Attribute[] attributes) {        InputMethodRequests req = getClientInputMethodRequests();        if(req != null) {            return req.cancelLatestCommittedText(attributes);        }         // we don't have access to the client component's text.        return null;    }     public AttributedCharacterIterator getSelectedText(Attribute[] attributes) {        InputMethodRequests req = getClientInputMethodRequests();        if(req != null) {            return req.getSelectedText(attributes);        }         // we don't have access to the client component's text.        return EMPTY_TEXT;    } }