blob: f95b13c63ab752b17d990447b77764624ff3ac62 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1998-2003 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.awt.im;
27
28import java.awt.AWTException;
29import java.awt.CheckboxMenuItem;
30import java.awt.Component;
31import java.awt.Dialog;
32import java.awt.EventQueue;
33import java.awt.Frame;
34import java.awt.PopupMenu;
35import java.awt.Menu;
36import java.awt.MenuItem;
37import java.awt.Toolkit;
38import sun.awt.AppContext;
39import java.awt.event.ActionEvent;
40import java.awt.event.ActionListener;
41import java.awt.event.InvocationEvent;
42import java.awt.im.spi.InputMethodDescriptor;
43import java.lang.reflect.InvocationTargetException;
44import java.security.AccessController;
45import java.security.PrivilegedAction;
46import java.security.PrivilegedActionException;
47import java.security.PrivilegedExceptionAction;
48import java.util.Hashtable;
49import java.util.Iterator;
50import java.util.Locale;
51import java.util.ServiceLoader;
52import java.util.Vector;
53import java.util.Set;
54import java.util.prefs.BackingStoreException;
55import java.util.prefs.Preferences;
56import sun.awt.InputMethodSupport;
57import 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
131public 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 */
243class 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 }
362
363 Throwable eventThrowable = event.getThrowable();
364 if (eventThrowable != null) {
365 throw new InvocationTargetException(eventThrowable);
366 }
367 }
368
369 void setInputContext(InputContext inputContext) {
370 if (currentInputContext != null && inputContext != null) {
371 // don't throw this exception until 4237852 is fixed
372 // throw new IllegalStateException("Can't have two active InputContext at the same time");
373 }
374 currentInputContext = inputContext;
375 }
376
377 public synchronized void notifyChangeRequest(Component comp) {
378 if (!(comp instanceof Frame || comp instanceof Dialog))
379 return;
380
381 // if busy with the current request, ignore this request.
382 if (requestComponent != null)
383 return;
384
385 requestComponent = comp;
386 notify();
387 }
388
389 public synchronized void notifyChangeRequestByHotKey(Component comp) {
390 while (!(comp instanceof Frame || comp instanceof Dialog)) {
391 if (comp == null) {
392 // no Frame or Dialog found in containment hierarchy.
393 return;
394 }
395 comp = comp.getParent();
396 }
397
398 notifyChangeRequest(comp);
399 }
400
401 public String getTriggerMenuString() {
402 return triggerMenuString;
403 }
404
405 /*
406 * Returns true if the environment indicates there are multiple input methods
407 */
408 boolean hasMultipleInputMethods() {
409 return ((hostAdapterLocator != null) && (javaInputMethodCount > 0)
410 || (javaInputMethodCount > 1));
411 }
412
413 private synchronized void waitForChangeRequest() {
414 try {
415 while (requestComponent == null) {
416 wait();
417 }
418 } catch (InterruptedException e) {
419 }
420 }
421
422 /*
423 * initializes the input method locator list for all
424 * installed input method descriptors.
425 */
426 private void initializeInputMethodLocatorList() {
427 synchronized (javaInputMethodLocatorList) {
428 javaInputMethodLocatorList.clear();
429 try {
430 AccessController.doPrivileged(new PrivilegedExceptionAction() {
431 public Object run() {
432 for (InputMethodDescriptor descriptor :
433 ServiceLoader.loadInstalled(InputMethodDescriptor.class)) {
434 ClassLoader cl = descriptor.getClass().getClassLoader();
435 javaInputMethodLocatorList.add(new InputMethodLocator(descriptor, cl, null));
436 }
437 return null;
438 }
439 });
440 } catch (PrivilegedActionException e) {
441 e.printStackTrace();
442 }
443 javaInputMethodCount = javaInputMethodLocatorList.size();
444 }
445
446 if (hasMultipleInputMethods()) {
447 // initialize preferences
448 if (userRoot == null) {
449 userRoot = getUserRoot();
450 }
451 } else {
452 // indicate to clients not to offer the menu
453 triggerMenuString = null;
454 }
455 }
456
457 private void showInputMethodMenu() {
458
459 if (!hasMultipleInputMethods()) {
460 requestComponent = null;
461 return;
462 }
463
464 // initialize pop-up menu
465 selectionMenu = InputMethodPopupMenu.getInstance(requestComponent, selectInputMethodMenuTitle);
466
467 // we have to rebuild the menu each time because
468 // some input methods (such as IIIMP) may change
469 // their list of supported locales dynamically
470 selectionMenu.removeAll();
471
472 // get information about the currently selected input method
473 // ??? if there's no current input context, what's the point
474 // of showing the menu?
475 String currentSelection = getCurrentSelection();
476
477 // Add menu item for host adapter
478 if (hostAdapterLocator != null) {
479 selectionMenu.addOneInputMethodToMenu(hostAdapterLocator, currentSelection);
480 selectionMenu.addSeparator();
481 }
482
483 // Add menu items for other input methods
484 for (int i = 0; i < javaInputMethodLocatorList.size(); i++) {
485 InputMethodLocator locator = javaInputMethodLocatorList.get(i);
486 selectionMenu.addOneInputMethodToMenu(locator, currentSelection);
487 }
488
489 synchronized (this) {
490 selectionMenu.addToComponent(requestComponent);
491 requestInputContext = currentInputContext;
492 selectionMenu.show(requestComponent, 60, 80); // TODO: get proper x, y...
493 requestComponent = null;
494 }
495 }
496
497 private String getCurrentSelection() {
498 InputContext inputContext = currentInputContext;
499 if (inputContext != null) {
500 InputMethodLocator locator = inputContext.getInputMethodLocator();
501 if (locator != null) {
502 return locator.getActionCommandString();
503 }
504 }
505 return null;
506 }
507
508 synchronized void changeInputMethod(String choice) {
509 InputMethodLocator locator = null;
510
511 String inputMethodName = choice;
512 String localeString = null;
513 int index = choice.indexOf('\n');
514 if (index != -1) {
515 localeString = choice.substring(index + 1);
516 inputMethodName = choice.substring(0, index);
517 }
518 if (hostAdapterLocator.getActionCommandString().equals(inputMethodName)) {
519 locator = hostAdapterLocator;
520 } else {
521 for (int i = 0; i < javaInputMethodLocatorList.size(); i++) {
522 InputMethodLocator candidate = javaInputMethodLocatorList.get(i);
523 String name = candidate.getActionCommandString();
524 if (name.equals(inputMethodName)) {
525 locator = candidate;
526 break;
527 }
528 }
529 }
530
531 if (locator != null && localeString != null) {
532 String language = "", country = "", variant = "";
533 int postIndex = localeString.indexOf('_');
534 if (postIndex == -1) {
535 language = localeString;
536 } else {
537 language = localeString.substring(0, postIndex);
538 int preIndex = postIndex + 1;
539 postIndex = localeString.indexOf('_', preIndex);
540 if (postIndex == -1) {
541 country = localeString.substring(preIndex);
542 } else {
543 country = localeString.substring(preIndex, postIndex);
544 variant = localeString.substring(postIndex + 1);
545 }
546 }
547 Locale locale = new Locale(language, country, variant);
548 locator = locator.deriveLocator(locale);
549 }
550
551 if (locator == null)
552 return;
553
554 // tell the input context about the change
555 if (requestInputContext != null) {
556 requestInputContext.changeInputMethod(locator);
557 requestInputContext = null;
558
559 // remember the selection
560 putPreferredInputMethod(locator);
561 }
562 }
563
564 InputMethodLocator findInputMethod(Locale locale) {
565 // look for preferred input method first
566 InputMethodLocator locator = getPreferredInputMethod(locale);
567 if (locator != null) {
568 return locator;
569 }
570
571 if (hostAdapterLocator != null && hostAdapterLocator.isLocaleAvailable(locale)) {
572 return hostAdapterLocator.deriveLocator(locale);
573 }
574
575 // Update the locator list
576 initializeInputMethodLocatorList();
577
578 for (int i = 0; i < javaInputMethodLocatorList.size(); i++) {
579 InputMethodLocator candidate = javaInputMethodLocatorList.get(i);
580 if (candidate.isLocaleAvailable(locale)) {
581 return candidate.deriveLocator(locale);
582 }
583 }
584 return null;
585 }
586
587 Locale getDefaultKeyboardLocale() {
588 Toolkit toolkit = Toolkit.getDefaultToolkit();
589 if (toolkit instanceof InputMethodSupport) {
590 return ((InputMethodSupport)toolkit).getDefaultKeyboardLocale();
591 } else {
592 return Locale.getDefault();
593 }
594 }
595
596 /**
597 * Returns a InputMethodLocator object that the
598 * user prefers for the given locale.
599 *
600 * @param locale Locale for which the user prefers the input method.
601 */
602 private synchronized InputMethodLocator getPreferredInputMethod(Locale locale) {
603 InputMethodLocator preferredLocator = null;
604
605 if (!hasMultipleInputMethods()) {
606 // No need to look for a preferred Java input method
607 return null;
608 }
609
610 // look for the cached preference first.
611 preferredLocator = (InputMethodLocator)preferredLocatorCache.get(locale.toString().intern());
612 if (preferredLocator != null) {
613 return preferredLocator;
614 }
615
616 // look for the preference in the user preference tree
617 String nodePath = findPreferredInputMethodNode(locale);
618 String descriptorName = readPreferredInputMethod(nodePath);
619 Locale advertised;
620
621 // get the locator object
622 if (descriptorName != null) {
623 // check for the host adapter first
624 if (hostAdapterLocator != null &&
625 hostAdapterLocator.getDescriptor().getClass().getName().equals(descriptorName)) {
626 advertised = getAdvertisedLocale(hostAdapterLocator, locale);
627 if (advertised != null) {
628 preferredLocator = hostAdapterLocator.deriveLocator(advertised);
629 preferredLocatorCache.put(locale.toString().intern(), preferredLocator);
630 }
631 return preferredLocator;
632 }
633 // look for Java input methods
634 for (int i = 0; i < javaInputMethodLocatorList.size(); i++) {
635 InputMethodLocator locator = javaInputMethodLocatorList.get(i);
636 InputMethodDescriptor descriptor = locator.getDescriptor();
637 if (descriptor.getClass().getName().equals(descriptorName)) {
638 advertised = getAdvertisedLocale(locator, locale);
639 if (advertised != null) {
640 preferredLocator = locator.deriveLocator(advertised);
641 preferredLocatorCache.put(locale.toString().intern(), preferredLocator);
642 }
643 return preferredLocator;
644 }
645 }
646
647 // maybe preferred input method information is bogus.
648 writePreferredInputMethod(nodePath, null);
649 }
650
651 return null;
652 }
653
654 private String findPreferredInputMethodNode(Locale locale) {
655 if (userRoot == null) {
656 return null;
657 }
658
659 // create locale node relative path
660 String nodePath = preferredIMNode + "/" + createLocalePath(locale);
661
662 // look for the descriptor
663 while (!nodePath.equals(preferredIMNode)) {
664 try {
665 if (userRoot.nodeExists(nodePath)) {
666 if (readPreferredInputMethod(nodePath) != null) {
667 return nodePath;
668 }
669 }
670 } catch (BackingStoreException bse) {
671 }
672
673 // search at parent's node
674 nodePath = nodePath.substring(0, nodePath.lastIndexOf('/'));
675 }
676
677 return null;
678 }
679
680 private String readPreferredInputMethod(String nodePath) {
681 if ((userRoot == null) || (nodePath == null)) {
682 return null;
683 }
684
685 return userRoot.node(nodePath).get(descriptorKey, null);
686 }
687
688 /**
689 * Writes the preferred input method descriptor class name into
690 * the user's Preferences tree in accordance with the given locale.
691 *
692 * @param inputMethodLocator input method locator to remember.
693 */
694 private synchronized void putPreferredInputMethod(InputMethodLocator locator) {
695 InputMethodDescriptor descriptor = locator.getDescriptor();
696 Locale preferredLocale = locator.getLocale();
697
698 if (preferredLocale == null) {
699 // check available locales of the input method
700 try {
701 Locale[] availableLocales = descriptor.getAvailableLocales();
702 if (availableLocales.length == 1) {
703 preferredLocale = availableLocales[0];
704 } else {
705 // there is no way to know which locale is the preferred one, so do nothing.
706 return;
707 }
708 } catch (AWTException ae) {
709 // do nothing here, either.
710 return;
711 }
712 }
713
714 // for regions that have only one language, we need to regard
715 // "xx_YY" as "xx" when putting the preference into tree
716 if (preferredLocale.equals(Locale.JAPAN)) {
717 preferredLocale = Locale.JAPANESE;
718 }
719 if (preferredLocale.equals(Locale.KOREA)) {
720 preferredLocale = Locale.KOREAN;
721 }
722 if (preferredLocale.equals(new Locale("th", "TH"))) {
723 preferredLocale = new Locale("th");
724 }
725
726 // obtain node
727 String path = preferredIMNode + "/" + createLocalePath(preferredLocale);
728
729 // write in the preference tree
730 writePreferredInputMethod(path, descriptor.getClass().getName());
731 preferredLocatorCache.put(preferredLocale.toString().intern(),
732 locator.deriveLocator(preferredLocale));
733
734 return;
735 }
736
737 private String createLocalePath(Locale locale) {
738 String language = locale.getLanguage();
739 String country = locale.getCountry();
740 String variant = locale.getVariant();
741 String localePath = null;
742 if (!variant.equals("")) {
743 localePath = "_" + language + "/_" + country + "/_" + variant;
744 } else if (!country.equals("")) {
745 localePath = "_" + language + "/_" + country;
746 } else {
747 localePath = "_" + language;
748 }
749
750 return localePath;
751 }
752
753 private void writePreferredInputMethod(String path, String descriptorName) {
754 if (userRoot != null) {
755 Preferences node = userRoot.node(path);
756
757 // record it
758 if (descriptorName != null) {
759 node.put(descriptorKey, descriptorName);
760 } else {
761 node.remove(descriptorKey);
762 }
763 }
764 }
765
766 private Preferences getUserRoot() {
767 return (Preferences)AccessController.doPrivileged(new PrivilegedAction() {
768 public Object run() {
769 return Preferences.userRoot();
770 }
771 });
772 }
773
774 private Locale getAdvertisedLocale(InputMethodLocator locator, Locale locale) {
775 Locale advertised = null;
776
777 if (locator.isLocaleAvailable(locale)) {
778 advertised = locale;
779 } else if (locale.getLanguage().equals("ja")) {
780 // for Japanese, Korean, and Thai, check whether the input method supports
781 // language or language_COUNTRY.
782 if (locator.isLocaleAvailable(Locale.JAPAN)) {
783 advertised = Locale.JAPAN;
784 } else if (locator.isLocaleAvailable(Locale.JAPANESE)) {
785 advertised = Locale.JAPANESE;
786 }
787 } else if (locale.getLanguage().equals("ko")) {
788 if (locator.isLocaleAvailable(Locale.KOREA)) {
789 advertised = Locale.KOREA;
790 } else if (locator.isLocaleAvailable(Locale.KOREAN)) {
791 advertised = Locale.KOREAN;
792 }
793 } else if (locale.getLanguage().equals("th")) {
794 if (locator.isLocaleAvailable(new Locale("th", "TH"))) {
795 advertised = new Locale("th", "TH");
796 } else if (locator.isLocaleAvailable(new Locale("th"))) {
797 advertised = new Locale("th");
798 }
799 }
800
801 return advertised;
802 }
803}