Home » openjdk-7 » sun » awt » im » [javadoc | source]

    1   /*
    2    * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package sun.awt.im;
   27   
   28   import java.awt.AWTEvent;
   29   import java.awt.Component;
   30   import java.awt.GraphicsEnvironment;
   31   import java.awt.HeadlessException;
   32   import java.awt.Rectangle;
   33   import java.awt.Toolkit;
   34   import java.awt.Window;
   35   import java.awt.event.KeyEvent;
   36   import java.awt.event.InputMethodEvent;
   37   import java.awt.font.TextHitInfo;
   38   import java.awt.im.InputMethodRequests;
   39   import java.awt.im.spi.InputMethod;
   40   import java.security.AccessController;
   41   import java.text.AttributedCharacterIterator;
   42   import java.text.AttributedCharacterIterator.Attribute;
   43   import java.text.AttributedString;
   44   import java.text.CharacterIterator;
   45   import javax.swing.JFrame;
   46   import sun.awt.InputMethodSupport;
   47   import sun.security.action.GetPropertyAction;
   48   
   49   /**
   50    * The InputMethodContext class provides methods that input methods
   51    * can use to communicate with their client components.
   52    * It is a subclass of InputContext, which provides methods for use by
   53    * components.
   54    *
   55    * @author JavaSoft International
   56    */
   57   
   58   public class InputMethodContext
   59          extends sun.awt.im.InputContext
   60          implements java.awt.im.spi.InputMethodContext {
   61   
   62       private boolean dispatchingCommittedText;
   63   
   64       // Creation of the context's composition area handler is
   65       // delayed until we really need a composition area.
   66       private CompositionAreaHandler compositionAreaHandler;
   67       private Object compositionAreaHandlerLock = new Object();
   68   
   69       static private boolean belowTheSpotInputRequested;
   70       private boolean inputMethodSupportsBelowTheSpot;
   71   
   72       static {
   73           // check whether we should use below-the-spot input
   74           // get property from command line
   75           String inputStyle = (String) AccessController.doPrivileged
   76                   (new GetPropertyAction("java.awt.im.style", null));
   77           // get property from awt.properties file
   78           if (inputStyle == null) {
   79               inputStyle = Toolkit.getDefaultToolkit().
   80                       getProperty("java.awt.im.style", null);
   81           }
   82           belowTheSpotInputRequested = "below-the-spot".equals(inputStyle);
   83       }
   84   
   85       /**
   86        * Constructs an InputMethodContext.
   87        */
   88       public InputMethodContext() {
   89           super();
   90       }
   91   
   92       void setInputMethodSupportsBelowTheSpot(boolean supported) {
   93           inputMethodSupportsBelowTheSpot = supported;
   94       }
   95   
   96      boolean useBelowTheSpotInput() {
   97           return belowTheSpotInputRequested && inputMethodSupportsBelowTheSpot;
   98       }
   99   
  100       private boolean haveActiveClient() {
  101           Component client = getClientComponent();
  102           return client != null
  103                  && client.getInputMethodRequests() != null;
  104       }
  105   
  106       // implements java.awt.im.spi.InputMethodContext.dispatchInputMethodEvent
  107       public void dispatchInputMethodEvent(int id,
  108                   AttributedCharacterIterator text, int committedCharacterCount,
  109                   TextHitInfo caret, TextHitInfo visiblePosition) {
  110           // We need to record the client component as the source so
  111           // that we have correct information if we later have to break up this
  112           // event into key events.
  113           Component source;
  114   
  115           source = getClientComponent();
  116           if (source != null) {
  117               InputMethodEvent event = new InputMethodEvent(source,
  118                       id, text, committedCharacterCount, caret, visiblePosition);
  119   
  120               if (haveActiveClient() && !useBelowTheSpotInput()) {
  121                   source.dispatchEvent(event);
  122               } else {
  123                   getCompositionAreaHandler(true).processInputMethodEvent(event);
  124               }
  125           }
  126       }
  127   
  128       /**
  129        * Dispatches committed text to a client component.
  130        * Called by composition window.
  131        *
  132        * @param client The component that the text should get dispatched to.
  133        * @param text The iterator providing access to the committed
  134        *        (and possible composed) text.
  135        * @param committedCharacterCount The number of committed characters in the text.
  136        */
  137       synchronized void dispatchCommittedText(Component client,
  138                    AttributedCharacterIterator text,
  139                    int committedCharacterCount) {
  140           // note that the client is not always the current client component -
  141           // some host input method adapters may dispatch input method events
  142           // through the Java event queue, and we may have switched clients while
  143           // the event was in the queue.
  144           if (committedCharacterCount == 0
  145                   || text.getEndIndex() <= text.getBeginIndex()) {
  146               return;
  147           }
  148           long time = System.currentTimeMillis();
  149           dispatchingCommittedText = true;
  150           try {
  151               InputMethodRequests req = client.getInputMethodRequests();
  152               if (req != null) {
  153                   // active client -> send text as InputMethodEvent
  154                   int beginIndex = text.getBeginIndex();
  155                   AttributedCharacterIterator toBeCommitted =
  156                       (new AttributedString(text, beginIndex, beginIndex + committedCharacterCount)).getIterator();
  157   
  158                   InputMethodEvent inputEvent = new InputMethodEvent(
  159                           client,
  160                           InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
  161                           toBeCommitted,
  162                           committedCharacterCount,
  163                           null, null);
  164   
  165                   client.dispatchEvent(inputEvent);
  166               } else {
  167                   // passive client -> send text as KeyEvents
  168                   char keyChar = text.first();
  169                   while (committedCharacterCount-- > 0 && keyChar != CharacterIterator.DONE) {
  170                       KeyEvent keyEvent = new KeyEvent(client, KeyEvent.KEY_TYPED,
  171                                                    time, 0, KeyEvent.VK_UNDEFINED, keyChar);
  172                       client.dispatchEvent(keyEvent);
  173                       keyChar = text.next();
  174                   }
  175               }
  176           } finally {
  177               dispatchingCommittedText = false;
  178           }
  179       }
  180   
  181       public void dispatchEvent(AWTEvent event) {
  182           // some host input method adapters may dispatch input method events
  183           // through the Java event queue. If the component that the event is
  184           // intended for isn't an active client, or if we're using below-the-spot
  185           // input, we need to dispatch this event
  186           // to the input window. Note that that component is not necessarily the
  187           // current client component, since we may have switched clients while
  188           // the event was in the queue.
  189           if (event instanceof InputMethodEvent) {
  190               if (((Component) event.getSource()).getInputMethodRequests() == null
  191                       || (useBelowTheSpotInput() && !dispatchingCommittedText)) {
  192                   getCompositionAreaHandler(true).processInputMethodEvent((InputMethodEvent) event);
  193               }
  194           } else {
  195               // make sure we don't dispatch our own key events back to the input method
  196               if (!dispatchingCommittedText) {
  197                   super.dispatchEvent(event);
  198               }
  199           }
  200       }
  201   
  202       /**
  203        * Gets this context's composition area handler, creating it if necessary.
  204        * If requested, it grabs the composition area for use by this context.
  205        * The composition area's text is not updated.
  206        */
  207       private CompositionAreaHandler getCompositionAreaHandler(boolean grab) {
  208           synchronized(compositionAreaHandlerLock) {
  209               if (compositionAreaHandler == null) {
  210                   compositionAreaHandler = new CompositionAreaHandler(this);
  211               }
  212               compositionAreaHandler.setClientComponent(getClientComponent());
  213               if (grab) {
  214                   compositionAreaHandler.grabCompositionArea(false);
  215               }
  216   
  217               return compositionAreaHandler;
  218           }
  219       }
  220   
  221       /**
  222        * Grabs the composition area for use by this context.
  223        * If doUpdate is true, updates the composition area with previously sent
  224        * composed text.
  225        */
  226       void grabCompositionArea(boolean doUpdate) {
  227           synchronized(compositionAreaHandlerLock) {
  228               if (compositionAreaHandler != null) {
  229                   compositionAreaHandler.grabCompositionArea(doUpdate);
  230               } else {
  231                   // if this context hasn't seen a need for a composition area yet,
  232                   // just close it without creating the machinery
  233                   CompositionAreaHandler.closeCompositionArea();
  234               }
  235           }
  236       }
  237   
  238       /**
  239        * Releases and closes the composition area if it is currently owned by
  240        * this context's composition area handler.
  241        */
  242       void releaseCompositionArea() {
  243           synchronized(compositionAreaHandlerLock) {
  244               if (compositionAreaHandler != null) {
  245                   compositionAreaHandler.releaseCompositionArea();
  246               }
  247           }
  248       }
  249   
  250       /**
  251        * Calls CompositionAreaHandler.isCompositionAreaVisible() to see
  252        * whether the composition area is visible or not.
  253        * Notice that this method is always called on the AWT event dispatch
  254        * thread.
  255        */
  256       boolean isCompositionAreaVisible() {
  257           if (compositionAreaHandler != null) {
  258               return compositionAreaHandler.isCompositionAreaVisible();
  259           }
  260   
  261           return false;
  262       }
  263       /**
  264        * Calls CompositionAreaHandler.setCompositionAreaVisible to
  265        * show or hide the composition area.
  266        * As isCompositionAreaVisible method, it is always called
  267        * on AWT event dispatch thread.
  268        */
  269       void setCompositionAreaVisible(boolean visible) {
  270           if (compositionAreaHandler != null) {
  271               compositionAreaHandler.setCompositionAreaVisible(visible);
  272           }
  273       }
  274   
  275       /**
  276        * Calls the current client component's implementation of getTextLocation.
  277        */
  278       public Rectangle getTextLocation(TextHitInfo offset) {
  279           return getReq().getTextLocation(offset);
  280       }
  281   
  282       /**
  283        * Calls the current client component's implementation of getLocationOffset.
  284        */
  285       public TextHitInfo getLocationOffset(int x, int y) {
  286           return getReq().getLocationOffset(x, y);
  287       }
  288   
  289       /**
  290        * Calls the current client component's implementation of getInsertPositionOffset.
  291        */
  292       public int getInsertPositionOffset() {
  293           return getReq().getInsertPositionOffset();
  294       }
  295   
  296       /**
  297        * Calls the current client component's implementation of getCommittedText.
  298        */
  299       public AttributedCharacterIterator getCommittedText(int beginIndex,
  300                                                          int endIndex,
  301                                                          Attribute[] attributes) {
  302           return getReq().getCommittedText(beginIndex, endIndex, attributes);
  303       }
  304   
  305       /**
  306        * Calls the current client component's implementation of getCommittedTextLength.
  307        */
  308       public int getCommittedTextLength() {
  309           return getReq().getCommittedTextLength();
  310       }
  311   
  312   
  313       /**
  314        * Calls the current client component's implementation of cancelLatestCommittedText.
  315        */
  316       public AttributedCharacterIterator cancelLatestCommittedText(Attribute[] attributes) {
  317           return getReq().cancelLatestCommittedText(attributes);
  318       }
  319   
  320       /**
  321        * Calls the current client component's implementation of getSelectedText.
  322        */
  323       public AttributedCharacterIterator getSelectedText(Attribute[] attributes) {
  324           return getReq().getSelectedText(attributes);
  325       }
  326   
  327       private InputMethodRequests getReq() {
  328           if (haveActiveClient() && !useBelowTheSpotInput()) {
  329               return getClientComponent().getInputMethodRequests();
  330           } else {
  331               return getCompositionAreaHandler(false);
  332           }
  333       }
  334   
  335       // implements java.awt.im.spi.InputMethodContext.createInputMethodWindow
  336       public Window createInputMethodWindow(String title, boolean attachToInputContext) {
  337           InputContext context = attachToInputContext ? this : null;
  338           return createInputMethodWindow(title, context, false);
  339       }
  340   
  341       // implements java.awt.im.spi.InputMethodContext.createInputMethodJFrame
  342       public JFrame createInputMethodJFrame(String title, boolean attachToInputContext) {
  343           InputContext context = attachToInputContext ? this : null;
  344           return (JFrame)createInputMethodWindow(title, context, true);
  345       }
  346   
  347       static Window createInputMethodWindow(String title, InputContext context, boolean isSwing) {
  348           if (GraphicsEnvironment.isHeadless()) {
  349               throw new HeadlessException();
  350           }
  351           if (isSwing) {
  352               return new InputMethodJFrame(title, context);
  353           } else {
  354               Toolkit toolkit = Toolkit.getDefaultToolkit();
  355               if (toolkit instanceof InputMethodSupport) {
  356                   return ((InputMethodSupport)toolkit).createInputMethodWindow(
  357                       title, context);
  358               }
  359           }
  360           throw new InternalError("Input methods must be supported");
  361       }
  362   
  363       /**
  364        * @see java.awt.im.spi.InputMethodContext#enableClientWindowNotification
  365        */
  366       public void enableClientWindowNotification(InputMethod inputMethod, boolean enable) {
  367           super.enableClientWindowNotification(inputMethod, enable);
  368       }
  369   
  370     /**
  371      * Disables or enables decorations for the composition window.
  372      */
  373      void setCompositionAreaUndecorated(boolean undecorated) {
  374           if (compositionAreaHandler != null) {
  375               compositionAreaHandler.setCompositionAreaUndecorated(undecorated);
  376           }
  377      }
  378   }

Home » openjdk-7 » sun » awt » im » [javadoc | source]