History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/awt/im/InputMethodManager.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/awt/im/InputMethodManager.java+806−0
@@ -0,0 +1,806 @@
1+/*
2+ * Copyright (c) 1998, 2003, 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.AWTException;
29+import java.awt.CheckboxMenuItem;
30+import java.awt.Component;
31+import java.awt.Dialog;
32+import java.awt.EventQueue;
33+import java.awt.Frame;
34+import java.awt.PopupMenu;
35+import java.awt.Menu;
36+import java.awt.MenuItem;
37+import java.awt.Toolkit;
38+import sun.awt.AppContext;
39+import java.awt.event.ActionEvent;
40+import java.awt.event.ActionListener;
41+import java.awt.event.InvocationEvent;
42+import java.awt.im.spi.InputMethodDescriptor;
43+import java.lang.reflect.InvocationTargetException;
44+import java.security.AccessController;
45+import java.security.PrivilegedAction;
46+import java.security.PrivilegedActionException;
47+import java.security.PrivilegedExceptionAction;
48+import java.util.Hashtable;
49+import java.util.Iterator;
50+import java.util.Locale;
51+import java.util.ServiceLoader;
52+import java.util.Vector;
53+import java.util.Set;
54+import java.util.prefs.BackingStoreException;
55+import java.util.prefs.Preferences;
56+import sun.awt.InputMethodSupport;
57+import sun.awt.SunToolkit;
58+
59+/**
60+ * <code>InputMethodManager</code> is an abstract class that manages the input
61+ * method environment of JVM. There is only one <code>InputMethodManager</code>
62+ * instance in JVM that is executed under a separate daemon thread.
63+ * <code>InputMethodManager</code> performs the following:
64+ * <UL>
65+ * <LI>
66+ * Keeps track of the current input context.</LI>
67+ *
68+ * <LI>
69+ * Provides a user interface to switch input methods and notifies the current
70+ * input context about changes made from the user interface.</LI>
71+ * </UL>
72+ *
73+ * The mechanism for supporting input method switch is as follows. (Note that
74+ * this may change in future releases.)
75+ *
76+ * <UL>
77+ * <LI>
78+ * One way is to use platform-dependent window manager's menu (known as the <I>Window
79+ * menu </I>in Motif and the <I>System menu</I> or <I>Control menu</I> in
80+ * Win32) on each window which is popped up by clicking the left top box of
81+ * a window (known as <I>Window menu button</I> in Motif and <I>System menu
82+ * button</I> in Win32). This happens to be common in both Motif and Win32.</LI>
83+ *
84+ * <LI>
85+ * When more than one input method descriptor can be found or the only input
86+ * method descriptor found supports multiple locales, a menu item
87+ * is added to the window (manager) menu. This item label is obtained invoking
88+ * <code>getTriggerMenuString()</code>. If null is returned by this method, it
89+ * means that there is only input method or none in the environment. Frame and Dialog
90+ * invoke this method.</LI>
91+ *
92+ * <LI>
93+ * This menu item means a trigger switch to the user to pop up a selection
94+ * menu.</LI>
95+ *
96+ * <LI>
97+ * When the menu item of the window (manager) menu has been selected by the
98+ * user, Frame/Dialog invokes <code>notifyChangeRequest()</code> to notify
99+ * <code>InputMethodManager</code> that the user wants to switch input methods.</LI>
100+ *
101+ * <LI>
102+ * <code>InputMethodManager</code> displays a pop-up menu to choose an input method.</LI>
103+ *
104+ * <LI>
105+ * <code>InputMethodManager</code> notifies the current <code>InputContext</code> of
106+ * the selected <code>InputMethod</code>.</LI>
107+ * </UL>
108+ *
109+ * <UL>
110+ * <LI>
111+ * The other way is to use user-defined hot key combination to show the pop-up menu to
112+ * choose an input method. This is useful for the platforms which do not provide a
113+ * way to add a menu item in the window (manager) menu.</LI>
114+ *
115+ * <LI>
116+ * When the hot key combination is typed by the user, the component which has the input
117+ * focus invokes <code>notifyChangeRequestByHotKey()</code> to notify
118+ * <code>InputMethodManager</code> that the user wants to switch input methods.</LI>
119+ *
120+ * <LI>
121+ * This results in a popup menu and notification to the current input context,
122+ * as above.</LI>
123+ * </UL>
124+ *
125+ * @see java.awt.im.spi.InputMethod
126+ * @see sun.awt.im.InputContext
127+ * @see sun.awt.im.InputMethodAdapter
128+ * @author JavaSoft International
129+ */
130+
131+public abstract class InputMethodManager {
132+
133+ /**
134+ * InputMethodManager thread name
135+ */
136+ private static final String threadName = "AWT-InputMethodManager";
137+
138+ /**
139+ * Object for global locking
140+ */
141+ private static final Object LOCK = new Object();
142+
143+ /**
144+ * The InputMethodManager instance
145+ */
146+ private static InputMethodManager inputMethodManager;
147+
148+ /**
149+ * Returns the instance of InputMethodManager. This method creates
150+ * the instance that is unique in the Java VM if it has not been
151+ * created yet.
152+ *
153+ * @return the InputMethodManager instance
154+ */
155+ public static final InputMethodManager getInstance() {
156+ if (inputMethodManager != null) {
157+ return inputMethodManager;
158+ }
159+ synchronized(LOCK) {
160+ if (inputMethodManager == null) {
161+ ExecutableInputMethodManager imm = new ExecutableInputMethodManager();
162+
163+ // Initialize the input method manager and start a
164+ // daemon thread if the user has multiple input methods
165+ // to choose from. Otherwise, just keep the instance.
166+ if (imm.hasMultipleInputMethods()) {
167+ imm.initialize();
168+ Thread immThread = new Thread(imm, threadName);
169+ immThread.setDaemon(true);
170+ immThread.setPriority(Thread.NORM_PRIORITY + 1);
171+ immThread.start();
172+ }
173+ inputMethodManager = imm;
174+ }
175+ }
176+ return inputMethodManager;
177+ }
178+
179+ /**
180+ * Gets a string for the trigger menu item that should be added to
181+ * the window manager menu. If no need to display the trigger menu
182+ * item, null is returned.
183+ */
184+ public abstract String getTriggerMenuString();
185+
186+ /**
187+ * Notifies InputMethodManager that input method change has been
188+ * requested by the user. This notification triggers a popup menu
189+ * for user selection.
190+ *
191+ * @param comp Component that has accepted the change
192+ * request. This component has to be a Frame or Dialog.
193+ */
194+ public abstract void notifyChangeRequest(Component comp);
195+
196+ /**
197+ * Notifies InputMethodManager that input method change has been
198+ * requested by the user using the hot key combination. This
199+ * notification triggers a popup menu for user selection.
200+ *
201+ * @param comp Component that has accepted the change
202+ * request. This component has the input focus.
203+ */
204+ public abstract void notifyChangeRequestByHotKey(Component comp);
205+
206+ /**
207+ * Sets the current input context so that it will be notified
208+ * of input method changes initiated from the user interface.
209+ * Set to real input context when activating; to null when
210+ * deactivating.
211+ */
212+ abstract void setInputContext(InputContext inputContext);
213+
214+ /**
215+ * Tries to find an input method locator for the given locale.
216+ * Returns null if no available input method locator supports
217+ * the locale.
218+ */
219+ abstract InputMethodLocator findInputMethod(Locale forLocale);
220+
221+ /**
222+ * Gets the default keyboard locale of the underlying operating system.
223+ */
224+ abstract Locale getDefaultKeyboardLocale();
225+
226+ /**
227+ * Returns whether multiple input methods are available or not
228+ */
229+ abstract boolean hasMultipleInputMethods();
230+
231+}
232+
233+/**
234+ * <code>ExecutableInputMethodManager</code> is the implementation of the
235+ * <code>InputMethodManager</code> class. It is runnable as a separate
236+ * thread in the AWT environment.&nbsp;
237+ * <code>InputMethodManager.getInstance()</code> creates an instance of
238+ * <code>ExecutableInputMethodManager</code> and executes it as a deamon
239+ * thread.
240+ *
241+ * @see InputMethodManager
242+ */
243+class ExecutableInputMethodManager extends InputMethodManager
244+ implements Runnable
245+{
246+ // the input context that's informed about selections from the user interface
247+ private InputContext currentInputContext;
248+
249+ // Menu item string for the trigger menu.
250+ private String triggerMenuString;
251+
252+ // popup menu for selecting an input method
253+ private InputMethodPopupMenu selectionMenu;
254+ private static String selectInputMethodMenuTitle;
255+
256+ // locator and name of host adapter
257+ private InputMethodLocator hostAdapterLocator;
258+
259+ // locators for Java input methods
260+ private int javaInputMethodCount; // number of Java input methods found
261+ private Vector<InputMethodLocator> javaInputMethodLocatorList;
262+
263+ // component that is requesting input method switch
264+ // must be Frame or Dialog
265+ private Component requestComponent;
266+
267+ // input context that is requesting input method switch
268+ private InputContext requestInputContext;
269+
270+ // IM preference stuff
271+ private static final String preferredIMNode = "/sun/awt/im/preferredInputMethod";
272+ private static final String descriptorKey = "descriptor";
273+ private Hashtable preferredLocatorCache = new Hashtable();
274+ private Preferences userRoot;
275+
276+ ExecutableInputMethodManager() {
277+
278+ // set up host adapter locator
279+ Toolkit toolkit = Toolkit.getDefaultToolkit();
280+ try {
281+ if (toolkit instanceof InputMethodSupport) {
282+ InputMethodDescriptor hostAdapterDescriptor =
283+ ((InputMethodSupport)toolkit)
284+ .getInputMethodAdapterDescriptor();
285+ if (hostAdapterDescriptor != null) {
286+ hostAdapterLocator = new InputMethodLocator(hostAdapterDescriptor, null, null);
287+ }
288+ }
289+ } catch (AWTException e) {
290+ // if we can't get a descriptor, we'll just have to do without native input methods
291+ }
292+
293+ javaInputMethodLocatorList = new Vector<InputMethodLocator>();
294+ initializeInputMethodLocatorList();
295+ }
296+
297+ synchronized void initialize() {
298+ selectInputMethodMenuTitle = Toolkit.getProperty("AWT.InputMethodSelectionMenu", "Select Input Method");
299+
300+ triggerMenuString = selectInputMethodMenuTitle;
301+ }
302+
303+ public void run() {
304+ // If there are no multiple input methods to choose from, wait forever
305+ while (!hasMultipleInputMethods()) {
306+ try {
307+ synchronized (this) {
308+ wait();
309+ }
310+ } catch (InterruptedException e) {
311+ }
312+ }
313+
314+ // Loop for processing input method change requests
315+ while (true) {
316+ waitForChangeRequest();
317+ initializeInputMethodLocatorList();
318+ try {
319+ if (requestComponent != null) {
320+ showInputMethodMenuOnRequesterEDT(requestComponent);
321+ } else {
322+ // show the popup menu within the event thread
323+ EventQueue.invokeAndWait(new Runnable() {
324+ public void run() {
325+ showInputMethodMenu();
326+ }
327+ });
328+ }
329+ } catch (InterruptedException ie) {
330+ } catch (InvocationTargetException ite) {
331+ // should we do anything under these exceptions?
332+ }
333+ }
334+ }
335+
336+ // Shows Input Method Menu on the EDT of requester component
337+ // to avoid side effects. See 6544309.
338+ private void showInputMethodMenuOnRequesterEDT(Component requester)
339+ throws InterruptedException, InvocationTargetException {
340+
341+ if (requester == null){
342+ return;
343+ }
344+
345+ class AWTInvocationLock {}
346+ Object lock = new AWTInvocationLock();
347+
348+ InvocationEvent event =
349+ new InvocationEvent(requester,
350+ new Runnable() {
351+ public void run() {
352+ showInputMethodMenu();
353+ }
354+ },
355+ lock,
356+ true);
357+
358+ AppContext requesterAppContext = SunToolkit.targetToAppContext(requester);
359+ synchronized (lock) {
360+ SunToolkit.postEvent(requesterAppContext, event);
361+ while (!event.isDispatched()) {
362+ lock.wait();
363+ }
364+ }
365+
366+ Throwable eventThrowable = event.getThrowable();
367+ if (eventThrowable != null) {
368+ throw new InvocationTargetException(eventThrowable);
369+ }
370+ }
371+
372+ void setInputContext(InputContext inputContext) {
373+ if (currentInputContext != null && inputContext != null) {
374+ // don't throw this exception until 4237852 is fixed
375+ // throw new IllegalStateException("Can't have two active InputContext at the same time");
376+ }
377+ currentInputContext = inputContext;
378+ }
379+
380+ public synchronized void notifyChangeRequest(Component comp) {
381+ if (!(comp instanceof Frame || comp instanceof Dialog))
382+ return;
383+
384+ // if busy with the current request, ignore this request.
385+ if (requestComponent != null)
386+ return;
387+
388+ requestComponent = comp;
389+ notify();
390+ }
391+
392+ public synchronized void notifyChangeRequestByHotKey(Component comp) {
393+ while (!(comp instanceof Frame || comp instanceof Dialog)) {
394+ if (comp == null) {
395+ // no Frame or Dialog found in containment hierarchy.
396+ return;
397+ }
398+ comp = comp.getParent();
399+ }
400+
401+ notifyChangeRequest(comp);
402+ }
403+
404+ public String getTriggerMenuString() {
405+ return triggerMenuString;
406+ }
407+
408+ /*
409+ * Returns true if the environment indicates there are multiple input methods
410+ */
411+ boolean hasMultipleInputMethods() {
412+ return ((hostAdapterLocator != null) && (javaInputMethodCount > 0)
413+ || (javaInputMethodCount > 1));
414+ }
415+
416+ private synchronized void waitForChangeRequest() {
417+ try {
418+ while (requestComponent == null) {
419+ wait();
420+ }
421+ } catch (InterruptedException e) {
422+ }
423+ }
424+
425+ /*
426+ * initializes the input method locator list for all
427+ * installed input method descriptors.
428+ */
429+ private void initializeInputMethodLocatorList() {
430+ synchronized (javaInputMethodLocatorList) {
431+ javaInputMethodLocatorList.clear();
432+ try {
433+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
434+ public Object run() {
435+ for (InputMethodDescriptor descriptor :
436+ ServiceLoader.loadInstalled(InputMethodDescriptor.class)) {
437+ ClassLoader cl = descriptor.getClass().getClassLoader();
438+ javaInputMethodLocatorList.add(new InputMethodLocator(descriptor, cl, null));
439+ }
440+ return null;
441+ }
442+ });
443+ } catch (PrivilegedActionException e) {
444+ e.printStackTrace();
445+ }
446+ javaInputMethodCount = javaInputMethodLocatorList.size();
447+ }
448+
449+ if (hasMultipleInputMethods()) {
450+ // initialize preferences
451+ if (userRoot == null) {
452+ userRoot = getUserRoot();
453+ }
454+ } else {
455+ // indicate to clients not to offer the menu
456+ triggerMenuString = null;
457+ }
458+ }
459+
460+ private void showInputMethodMenu() {
461+
462+ if (!hasMultipleInputMethods()) {
463+ requestComponent = null;
464+ return;
465+ }
466+
467+ // initialize pop-up menu
468+ selectionMenu = InputMethodPopupMenu.getInstance(requestComponent, selectInputMethodMenuTitle);
469+
470+ // we have to rebuild the menu each time because
471+ // some input methods (such as IIIMP) may change
472+ // their list of supported locales dynamically
473+ selectionMenu.removeAll();
474+
475+ // get information about the currently selected input method
476+ // ??? if there's no current input context, what's the point
477+ // of showing the menu?
478+ String currentSelection = getCurrentSelection();
479+
480+ // Add menu item for host adapter
481+ if (hostAdapterLocator != null) {
482+ selectionMenu.addOneInputMethodToMenu(hostAdapterLocator, currentSelection);
483+ selectionMenu.addSeparator();
484+ }
485+
486+ // Add menu items for other input methods
487+ for (int i = 0; i < javaInputMethodLocatorList.size(); i++) {
488+ InputMethodLocator locator = javaInputMethodLocatorList.get(i);
489+ selectionMenu.addOneInputMethodToMenu(locator, currentSelection);
490+ }
491+
492+ synchronized (this) {
493+ selectionMenu.addToComponent(requestComponent);
494+ requestInputContext = currentInputContext;
495+ selectionMenu.show(requestComponent, 60, 80); // TODO: get proper x, y...
496+ requestComponent = null;
497+ }
498+ }
499+
500+ private String getCurrentSelection() {
501+ InputContext inputContext = currentInputContext;
502+ if (inputContext != null) {
503+ InputMethodLocator locator = inputContext.getInputMethodLocator();
504+ if (locator != null) {
505+ return locator.getActionCommandString();
506+ }
507+ }
508+ return null;
509+ }
510+
511+ synchronized void changeInputMethod(String choice) {
512+ InputMethodLocator locator = null;
513+
514+ String inputMethodName = choice;
515+ String localeString = null;
516+ int index = choice.indexOf('\n');
517+ if (index != -1) {
518+ localeString = choice.substring(index + 1);
519+ inputMethodName = choice.substring(0, index);
520+ }
521+ if (hostAdapterLocator.getActionCommandString().equals(inputMethodName)) {
522+ locator = hostAdapterLocator;
523+ } else {
524+ for (int i = 0; i < javaInputMethodLocatorList.size(); i++) {
525+ InputMethodLocator candidate = javaInputMethodLocatorList.get(i);
526+ String name = candidate.getActionCommandString();
527+ if (name.equals(inputMethodName)) {
528+ locator = candidate;
529+ break;
530+ }
531+ }
532+ }
533+
534+ if (locator != null && localeString != null) {
535+ String language = "", country = "", variant = "";
536+ int postIndex = localeString.indexOf('_');
537+ if (postIndex == -1) {
538+ language = localeString;
539+ } else {
540+ language = localeString.substring(0, postIndex);
541+ int preIndex = postIndex + 1;
542+ postIndex = localeString.indexOf('_', preIndex);
543+ if (postIndex == -1) {
544+ country = localeString.substring(preIndex);
545+ } else {
546+ country = localeString.substring(preIndex, postIndex);
547+ variant = localeString.substring(postIndex + 1);
548+ }
549+ }
550+ Locale locale = new Locale(language, country, variant);
551+ locator = locator.deriveLocator(locale);
552+ }
553+
554+ if (locator == null)
555+ return;
556+
557+ // tell the input context about the change
558+ if (requestInputContext != null) {
559+ requestInputContext.changeInputMethod(locator);
560+ requestInputContext = null;
561+
562+ // remember the selection
563+ putPreferredInputMethod(locator);
564+ }
565+ }
566+
567+ InputMethodLocator findInputMethod(Locale locale) {
568+ // look for preferred input method first
569+ InputMethodLocator locator = getPreferredInputMethod(locale);
570+ if (locator != null) {
571+ return locator;
572+ }
573+
574+ if (hostAdapterLocator != null && hostAdapterLocator.isLocaleAvailable(locale)) {
575+ return hostAdapterLocator.deriveLocator(locale);
576+ }
577+
578+ // Update the locator list
579+ initializeInputMethodLocatorList();
580+
581+ for (int i = 0; i < javaInputMethodLocatorList.size(); i++) {
582+ InputMethodLocator candidate = javaInputMethodLocatorList.get(i);
583+ if (candidate.isLocaleAvailable(locale)) {
584+ return candidate.deriveLocator(locale);
585+ }
586+ }
587+ return null;
588+ }
589+
590+ Locale getDefaultKeyboardLocale() {
591+ Toolkit toolkit = Toolkit.getDefaultToolkit();
592+ if (toolkit instanceof InputMethodSupport) {
593+ return ((InputMethodSupport)toolkit).getDefaultKeyboardLocale();
594+ } else {
595+ return Locale.getDefault();
596+ }
597+ }
598+
599+ /**
600+ * Returns a InputMethodLocator object that the
601+ * user prefers for the given locale.
602+ *
603+ * @param locale Locale for which the user prefers the input method.
604+ */
605+ private synchronized InputMethodLocator getPreferredInputMethod(Locale locale) {
606+ InputMethodLocator preferredLocator = null;
607+
608+ if (!hasMultipleInputMethods()) {
609+ // No need to look for a preferred Java input method
610+ return null;
611+ }
612+
613+ // look for the cached preference first.
614+ preferredLocator = (InputMethodLocator)preferredLocatorCache.get(locale.toString().intern());
615+ if (preferredLocator != null) {
616+ return preferredLocator;
617+ }
618+
619+ // look for the preference in the user preference tree
620+ String nodePath = findPreferredInputMethodNode(locale);
621+ String descriptorName = readPreferredInputMethod(nodePath);
622+ Locale advertised;
623+
624+ // get the locator object
625+ if (descriptorName != null) {
626+ // check for the host adapter first
627+ if (hostAdapterLocator != null &&
628+ hostAdapterLocator.getDescriptor().getClass().getName().equals(descriptorName)) {
629+ advertised = getAdvertisedLocale(hostAdapterLocator, locale);
630+ if (advertised != null) {
631+ preferredLocator = hostAdapterLocator.deriveLocator(advertised);
632+ preferredLocatorCache.put(locale.toString().intern(), preferredLocator);
633+ }
634+ return preferredLocator;
635+ }
636+ // look for Java input methods
637+ for (int i = 0; i < javaInputMethodLocatorList.size(); i++) {
638+ InputMethodLocator locator = javaInputMethodLocatorList.get(i);
639+ InputMethodDescriptor descriptor = locator.getDescriptor();
640+ if (descriptor.getClass().getName().equals(descriptorName)) {
641+ advertised = getAdvertisedLocale(locator, locale);
642+ if (advertised != null) {
643+ preferredLocator = locator.deriveLocator(advertised);
644+ preferredLocatorCache.put(locale.toString().intern(), preferredLocator);
645+ }
646+ return preferredLocator;
647+ }
648+ }
649+
650+ // maybe preferred input method information is bogus.
651+ writePreferredInputMethod(nodePath, null);
652+ }
653+
654+ return null;
655+ }
656+
657+ private String findPreferredInputMethodNode(Locale locale) {
658+ if (userRoot == null) {
659+ return null;
660+ }
661+
662+ // create locale node relative path
663+ String nodePath = preferredIMNode + "/" + createLocalePath(locale);
664+
665+ // look for the descriptor
666+ while (!nodePath.equals(preferredIMNode)) {
667+ try {
668+ if (userRoot.nodeExists(nodePath)) {
669+ if (readPreferredInputMethod(nodePath) != null) {
670+ return nodePath;
671+ }
672+ }
673+ } catch (BackingStoreException bse) {
674+ }
675+
676+ // search at parent's node
677+ nodePath = nodePath.substring(0, nodePath.lastIndexOf('/'));
678+ }
679+
680+ return null;
681+ }
682+
683+ private String readPreferredInputMethod(String nodePath) {
684+ if ((userRoot == null) || (nodePath == null)) {
685+ return null;
686+ }
687+
688+ return userRoot.node(nodePath).get(descriptorKey, null);
689+ }
690+
691+ /**
692+ * Writes the preferred input method descriptor class name into
693+ * the user's Preferences tree in accordance with the given locale.
694+ *
695+ * @param inputMethodLocator input method locator to remember.
696+ */
697+ private synchronized void putPreferredInputMethod(InputMethodLocator locator) {
698+ InputMethodDescriptor descriptor = locator.getDescriptor();
699+ Locale preferredLocale = locator.getLocale();
700+
701+ if (preferredLocale == null) {
702+ // check available locales of the input method
703+ try {
704+ Locale[] availableLocales = descriptor.getAvailableLocales();
705+ if (availableLocales.length == 1) {
706+ preferredLocale = availableLocales[0];
707+ } else {
708+ // there is no way to know which locale is the preferred one, so do nothing.
709+ return;
710+ }
711+ } catch (AWTException ae) {
712+ // do nothing here, either.
713+ return;
714+ }
715+ }
716+
717+ // for regions that have only one language, we need to regard
718+ // "xx_YY" as "xx" when putting the preference into tree
719+ if (preferredLocale.equals(Locale.JAPAN)) {
720+ preferredLocale = Locale.JAPANESE;
721+ }
722+ if (preferredLocale.equals(Locale.KOREA)) {
723+ preferredLocale = Locale.KOREAN;
724+ }
725+ if (preferredLocale.equals(new Locale("th", "TH"))) {
726+ preferredLocale = new Locale("th");
727+ }
728+
729+ // obtain node
730+ String path = preferredIMNode + "/" + createLocalePath(preferredLocale);
731+
732+ // write in the preference tree
733+ writePreferredInputMethod(path, descriptor.getClass().getName());
734+ preferredLocatorCache.put(preferredLocale.toString().intern(),
735+ locator.deriveLocator(preferredLocale));
736+
737+ return;
738+ }
739+
740+ private String createLocalePath(Locale locale) {
741+ String language = locale.getLanguage();
742+ String country = locale.getCountry();
743+ String variant = locale.getVariant();
744+ String localePath = null;
745+ if (!variant.equals("")) {
746+ localePath = "_" + language + "/_" + country + "/_" + variant;
747+ } else if (!country.equals("")) {
748+ localePath = "_" + language + "/_" + country;
749+ } else {
750+ localePath = "_" + language;
751+ }
752+
753+ return localePath;
754+ }
755+
756+ private void writePreferredInputMethod(String path, String descriptorName) {
757+ if (userRoot != null) {
758+ Preferences node = userRoot.node(path);
759+
760+ // record it
761+ if (descriptorName != null) {
762+ node.put(descriptorKey, descriptorName);
763+ } else {
764+ node.remove(descriptorKey);
765+ }
766+ }
767+ }
768+
769+ private Preferences getUserRoot() {
770+ return (Preferences)AccessController.doPrivileged(new PrivilegedAction() {
771+ public Object run() {
772+ return Preferences.userRoot();
773+ }
774+ });
775+ }
776+
777+ private Locale getAdvertisedLocale(InputMethodLocator locator, Locale locale) {
778+ Locale advertised = null;
779+
780+ if (locator.isLocaleAvailable(locale)) {
781+ advertised = locale;
782+ } else if (locale.getLanguage().equals("ja")) {
783+ // for Japanese, Korean, and Thai, check whether the input method supports
784+ // language or language_COUNTRY.
785+ if (locator.isLocaleAvailable(Locale.JAPAN)) {
786+ advertised = Locale.JAPAN;
787+ } else if (locator.isLocaleAvailable(Locale.JAPANESE)) {
788+ advertised = Locale.JAPANESE;
789+ }
790+ } else if (locale.getLanguage().equals("ko")) {
791+ if (locator.isLocaleAvailable(Locale.KOREA)) {
792+ advertised = Locale.KOREA;
793+ } else if (locator.isLocaleAvailable(Locale.KOREAN)) {
794+ advertised = Locale.KOREAN;
795+ }
796+ } else if (locale.getLanguage().equals("th")) {
797+ if (locator.isLocaleAvailable(new Locale("th", "TH"))) {
798+ advertised = new Locale("th", "TH");
799+ } else if (locator.isLocaleAvailable(new Locale("th"))) {
800+ advertised = new Locale("th");
801+ }
802+ }
803+
804+ return advertised;
805+ }
806+}