1 /* 2 * Copyright (c) 2003, 2007, 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.Container; 32 import java.awt.PopupMenu; 33 import java.awt.Menu; 34 import java.awt.MenuItem; 35 import java.awt.Toolkit; 36 import java.awt.event.ActionEvent; 37 import java.awt.event.ActionListener; 38 import java.awt.im.spi.InputMethodDescriptor; 39 import java.util.Locale; 40 import javax.swing.JCheckBoxMenuItem; 41 import javax.swing.JComponent; 42 import javax.swing.JDialog; 43 import javax.swing.JFrame; 44 import javax.swing.JPopupMenu; 45 import javax.swing.JMenu; 46 import javax.swing.JMenuItem; 47 import javax.swing.JWindow; 48 import javax.swing.SwingUtilities; 49 50 /** 51 * {@code InputMethodPopupMenu} provides the popup selection menu 52 */ 53 54 abstract class InputMethodPopupMenu implements ActionListener { 55 56 // Factory method to provide the menu, depending on the client, i.e., 57 // provide Swing popup menu if client is a swing app, otherwise AWT popup 58 // is created. 59 static InputMethodPopupMenu getInstance(Component client, String title) { 60 if ((client instanceof JFrame) || 61 (client instanceof JDialog) || 62 (client instanceof JWindow)) { 63 return new JInputMethodPopupMenu(title); 64 } else { 65 return new AWTInputMethodPopupMenu(title); 66 } 67 } 68 69 static InputMethodPopupMenu getAWTInstance(Component client, String title) { 70 return new AWTInputMethodPopupMenu(title); 71 } 72 73 abstract boolean isVisible(); 74 75 abstract void show(Component c, int x, int y); 76 77 abstract void removeAll(); 78 79 abstract void addSeparator(); 80 81 abstract void addToComponent(Component c); 82 83 abstract Object createSubmenu(String label); 84 85 abstract void add(Object menuItem); 86 87 abstract void addMenuItem(String label, String command, String currentSelection); 88 89 abstract void addMenuItem(Object targetMenu, String label, String command, 90 String currentSelection); 91 92 void addOneInputMethodToMenu(InputMethodLocator locator, String currentSelection) { 93 InputMethodDescriptor descriptor = locator.getDescriptor(); 94 String label = descriptor.getInputMethodDisplayName(null, Locale.getDefault()); 95 String command = locator.getActionCommandString(); 96 Locale[] locales = null; 97 int localeCount; 98 try { 99 locales = descriptor.getAvailableLocales(); 100 localeCount = locales.length; 101 } catch (AWTException e) { 102 // ??? should have better error handling - 103 // tell user what happened, then remove this input method from the list. 104 // For the time being, just show it disabled. 105 localeCount = 0; 106 } 107 if (localeCount == 0) { 108 // could be IIIMP adapter which has lost its connection 109 addMenuItem(label, null, currentSelection); 110 } else if (localeCount == 1) { 111 if (descriptor.hasDynamicLocaleList()) { 112 // try to make sure that what the user sees and what 113 // we eventually select is consistent even if the locale 114 // list changes in the meantime 115 label = descriptor.getInputMethodDisplayName(locales[0], Locale.getDefault()); 116 command = locator.deriveLocator(locales[0]).getActionCommandString(); 117 } 118 addMenuItem(label, command, currentSelection); 119 } else { 120 Object submenu = createSubmenu(label); 121 add(submenu); 122 for (int j = 0; j < localeCount; j++) { 123 Locale locale = locales[j]; 124 String subLabel = getLocaleName(locale); 125 String subCommand = locator.deriveLocator(locale).getActionCommandString(); 126 addMenuItem(submenu, subLabel, subCommand, currentSelection); 127 } 128 } 129 } 130 131 /** 132 * Returns whether command indicates the same input method as currentSelection, 133 * taking into account that command may not specify a locale where currentSelection does. 134 */ 135 static boolean isSelected(String command, String currentSelection) { 136 if (command == null || currentSelection == null) { 137 return false; 138 } 139 if (command.equals(currentSelection)) { 140 return true; 141 } 142 // currentSelection may indicate a locale where command does not 143 int index = currentSelection.indexOf('\n'); 144 if (index != -1 && currentSelection.substring(0, index).equals(command)) { 145 return true; 146 } 147 return false; 148 } 149 150 /** 151 * Returns a localized locale name for input methods with the 152 * given locale. It falls back to Locale.getDisplayName() and 153 * then to Locale.toString() if no localized locale name is found. 154 * 155 * @param locale Locale for which localized locale name is obtained 156 */ 157 String getLocaleName(Locale locale) { 158 String localeString = locale.toString(); 159 String localeName = Toolkit.getProperty("AWT.InputMethodLanguage." + localeString, null); 160 if (localeName == null) { 161 localeName = locale.getDisplayName(); 162 if (localeName == null || localeName.length() == 0) 163 localeName = localeString; 164 } 165 return localeName; 166 } 167 168 // ActionListener implementation 169 public void actionPerformed(ActionEvent event) { 170 String choice = event.getActionCommand(); 171 ((ExecutableInputMethodManager)InputMethodManager.getInstance()).changeInputMethod(choice); 172 } 173 174 } 175 176 class JInputMethodPopupMenu extends InputMethodPopupMenu { 177 static JPopupMenu delegate = null; 178 179 JInputMethodPopupMenu(String title) { 180 synchronized (this) { 181 if (delegate == null) { 182 delegate = new JPopupMenu(title); 183 } 184 } 185 } 186 187 boolean isVisible() { 188 return delegate.isVisible(); 189 } 190 191 void show(Component c, int x, int y) { 192 SwingUtilities.updateComponentTreeUI(delegate); 193 delegate.show(c, x, y); 194 } 195 196 void removeAll() { 197 delegate.removeAll(); 198 } 199 200 void addSeparator() { 201 delegate.addSeparator(); 202 } 203 204 void addToComponent(Component c) { 205 } 206 207 Object createSubmenu(String label) { 208 return new JMenu(label); 209 } 210 211 void add(Object menuItem) { 212 delegate.add((JMenuItem)menuItem); 213 } 214 215 void addMenuItem(String label, String command, String currentSelection) { 216 addMenuItem(delegate, label, command, currentSelection); 217 } 218 219 void addMenuItem(Object targetMenu, String label, String command, String currentSelection) { 220 JMenuItem menuItem; 221 if (isSelected(command, currentSelection)) { 222 menuItem = new JCheckBoxMenuItem(label, true); 223 } else { 224 menuItem = new JMenuItem(label); 225 } 226 menuItem.setActionCommand(command); 227 menuItem.addActionListener(this); 228 menuItem.setEnabled(command != null); 229 if (targetMenu instanceof JMenu) { 230 ((JMenu)targetMenu).add(menuItem); 231 } else { 232 ((JPopupMenu)targetMenu).add(menuItem); 233 } 234 } 235 236 } 237 238 class AWTInputMethodPopupMenu extends InputMethodPopupMenu { 239 static PopupMenu delegate = null; 240 241 AWTInputMethodPopupMenu(String title) { 242 synchronized (this) { 243 if (delegate == null) { 244 delegate = new PopupMenu(title); 245 } 246 } 247 } 248 249 boolean isVisible() { 250 return false; 251 } 252 253 void show(Component c, int x, int y) { 254 delegate.show(c, x, y); 255 } 256 257 void removeAll() { 258 delegate.removeAll(); 259 } 260 261 void addSeparator() { 262 delegate.addSeparator(); 263 } 264 265 void addToComponent(Component c) { 266 c.add(delegate); 267 } 268 269 Object createSubmenu(String label) { 270 return new Menu(label); 271 } 272 273 void add(Object menuItem) { 274 delegate.add((MenuItem)menuItem); 275 } 276 277 void addMenuItem(String label, String command, String currentSelection) { 278 addMenuItem(delegate, label, command, currentSelection); 279 } 280 281 void addMenuItem(Object targetMenu, String label, String command, String currentSelection) { 282 MenuItem menuItem; 283 if (isSelected(command, currentSelection)) { 284 menuItem = new CheckboxMenuItem(label, true); 285 } else { 286 menuItem = new MenuItem(label); 287 } 288 menuItem.setActionCommand(command); 289 menuItem.addActionListener(this); 290 menuItem.setEnabled(command != null); 291 ((Menu)targetMenu).add(menuItem); 292 } 293 }