diff --git a/platform/platform-api/src/com/intellij/openapi/keymap/KeyboardSettingsExternalizable.java b/platform/platform-api/src/com/intellij/openapi/keymap/KeyboardSettingsExternalizable.java new file mode 100644 index 000000000000..43f2a8ef7615 --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/keymap/KeyboardSettingsExternalizable.java @@ -0,0 +1,89 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.keymap; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.components.*; +import com.sun.istack.internal.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; + +/** + * @author Denis Fokin + */ + +@State( + name = "KeyboardSettings", + storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/keyboard.xml")} +) +public class KeyboardSettingsExternalizable implements PersistentStateComponent { + + private static final String [] supportedNonEnglishLanguages = {"de", "fr", "it"}; + + public static boolean isSupportedKeyboardLayout(@NotNull Component component) { + String keyboardLayoutLanguage = getLanguageForComponent(component); + for (String language : supportedNonEnglishLanguages) { + if (language.equals(keyboardLayoutLanguage)) { + return true; + } + } + return false; + } + + public static String getLanguageForComponent(@NotNull Component component) { + return component.getInputContext().getLocale().getLanguage(); + } + + public static String getDisplayLanguageNameForComponent(@NotNull Component component) { + return component.getInputContext().getLocale().getDisplayLanguage(); + } + + public static final class OptionSet { + public boolean USE_NON_ENGLISH_KEYBOARD = false; + } + + private OptionSet myOptions = new OptionSet(); + + public static KeyboardSettingsExternalizable getInstance() { + if (ApplicationManager.getApplication().isDisposed()) { + return new KeyboardSettingsExternalizable(); + } + else { + return ServiceManager.getService(KeyboardSettingsExternalizable.class); + } + } + + @Nullable + @Override + public OptionSet getState() { + return myOptions; + } + + @Override + public void loadState(OptionSet state) { + myOptions = state; + } + + public boolean isNonEnglishKeyboardSupportEnabled () { + return myOptions.USE_NON_ENGLISH_KEYBOARD; + } + + public void setNonEnglishKeyboardSupportEnabled (boolean enabled) { + myOptions.USE_NON_ENGLISH_KEYBOARD = enabled; + } + +} diff --git a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java index a33da1246a02..bfd8fecc4441 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java +++ b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java @@ -29,17 +29,16 @@ import com.intellij.openapi.application.impl.ApplicationImpl; import com.intellij.openapi.application.impl.LaterInvocator; import com.intellij.openapi.diagnostic.FrequentEventDetector; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.keymap.KeyboardSettingsExternalizable; import com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher; import com.intellij.openapi.keymap.impl.IdeMouseEventDispatcher; import com.intellij.openapi.keymap.impl.KeyState; -import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.ExpirableRunnable; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.wm.IdeFocusManager; -import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.ex.WindowManagerEx; import com.intellij.util.Alarm; import com.intellij.util.ReflectionUtil; @@ -411,7 +410,7 @@ public class IdeEventQueue extends EventQueue { //private static boolean altGrIsPressed = false; private static AWTEvent fixNonEnglishKeyboardLayouts(AWTEvent e) { - if (!Registry.is("ide.non.english.keyboard.layout.fix")) return e; + if (!KeyboardSettingsExternalizable.getInstance().isNonEnglishKeyboardSupportEnabled()) return e; if (e instanceof KeyEvent) { KeyEvent ke = (KeyEvent)e; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index 033912f36fc9..c26ebceac9f7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -875,6 +875,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } } + private static boolean firstCharTyped = true; + private void initComponent() { myPanel.setLayout(new BorderLayout()); @@ -930,6 +932,14 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } myEditorComponent.addKeyListener(new KeyListener() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() >= KeyEvent.VK_A && e.getKeyCode() <= KeyEvent.VK_Z) { + myCharKeyPressed = true; + } + KeyboardInternationalizationNotificationManager.showNotification(); + } + @Override public void keyTyped(@NotNull KeyEvent event) { myNeedToSelectPreviousChar = false; @@ -941,13 +951,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } } - @Override - public void keyPressed(KeyEvent e) { - if (e.getKeyCode() >= KeyEvent.VK_A && e.getKeyCode() <= KeyEvent.VK_Z) { - myCharKeyPressed = true; - } - } - @Override public void keyReleased(KeyEvent e) { myCharKeyPressed = false; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/KeyboardInternationalizationNotificationManager.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/KeyboardInternationalizationNotificationManager.java new file mode 100644 index 000000000000..cc251a7be79d --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/KeyboardInternationalizationNotificationManager.java @@ -0,0 +1,95 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.editor.impl; + +import com.intellij.notification.*; +import com.intellij.openapi.application.ApplicationNamesInfo; +import com.intellij.openapi.keymap.KeyboardSettingsExternalizable; +import com.intellij.openapi.keymap.impl.ui.KeymapPanel; +import com.intellij.openapi.options.ShowSettingsUtil; +import com.intellij.openapi.wm.IdeFrame; +import com.intellij.openapi.wm.ex.WindowManagerEx; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.event.HyperlinkEvent; +import java.awt.*; + +/** + * @author Denis Fokin + */ +public class KeyboardInternationalizationNotificationManager { + public static final String LOCALIZATION_GROUP_DISPLAY_ID = "Localization and Internationalization"; + public static boolean notificationHasBeenShown; + + private KeyboardInternationalizationNotificationManager() { + } + + public static void showNotification() { + + if (notificationHasBeenShown || !KeyboardSettingsExternalizable.isSupportedKeyboardLayout(WindowManagerEx.getInstanceEx().getMostRecentFocusedWindow())) return; + + MyNotificationListener listener = + new MyNotificationListener(); + + Notifications.Bus.notify(createNotification(LOCALIZATION_GROUP_DISPLAY_ID, listener)); + notificationHasBeenShown = true; + } + + public static Notification createNotification(@NotNull final String groupDisplayId, @Nullable NotificationListener listener) { + + final String productName = ApplicationNamesInfo.getInstance().getProductName(); + + Window recentFocusedWindow = WindowManagerEx.getInstanceEx().getMostRecentFocusedWindow(); + + String text = + "We have found out that you are using a non-english keyboard layout. You can enable smart layout support for " + + KeyboardSettingsExternalizable.getDisplayLanguageNameForComponent(recentFocusedWindow) + " language." + + "You can change this option in the settings of " + productName + " more..."; + + String title = "Enable smart keyboard internalization for " + productName + "."; + + return new Notification(groupDisplayId, title, + text, + NotificationType.INFORMATION, + listener); + } + + private static class MyNotificationListener implements NotificationListener { + + public MyNotificationListener() { + } + + @Override + public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { + if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + final String description = event.getDescription(); + if ("enable".equals(description)) { + KeyboardSettingsExternalizable.getInstance().setNonEnglishKeyboardSupportEnabled(true); + } + else if ("settings".equals(description)) { + final ShowSettingsUtil util = ShowSettingsUtil.getInstance(); + IdeFrame ideFrame = WindowManagerEx.getInstanceEx().findFrameFor(null); + //util.editConfigurable((JFrame)ideFrame, new StatisticsConfigurable(true)); + util.showSettingsDialog(ideFrame.getProject(), KeymapPanel.class); + } + + NotificationsConfiguration.getNotificationsConfiguration().changeSettings(LOCALIZATION_GROUP_DISPLAY_ID, NotificationDisplayType.NONE, false, false); + notification.expire(); + } + } + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeymapPanel.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeymapPanel.java index 582a3ef40a82..b3cb4f4e3417 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeymapPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeymapPanel.java @@ -26,10 +26,7 @@ import com.intellij.openapi.actionSystem.ex.QuickList; import com.intellij.openapi.actionSystem.ex.QuickListsManager; import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.keymap.KeyMapBundle; -import com.intellij.openapi.keymap.Keymap; -import com.intellij.openapi.keymap.KeymapManager; -import com.intellij.openapi.keymap.KeymapUtil; +import com.intellij.openapi.keymap.*; import com.intellij.openapi.keymap.ex.KeymapManagerEx; import com.intellij.openapi.keymap.impl.ActionShortcutRestrictions; import com.intellij.openapi.keymap.impl.KeymapImpl; @@ -52,6 +49,9 @@ import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.openapi.wm.IdeFrame; +import com.intellij.openapi.wm.impl.IdeFocusManagerImpl; import com.intellij.packageDependencies.ui.TreeExpansionMonitor; import com.intellij.ui.DocumentAdapter; import com.intellij.ui.DoubleClickListener; @@ -91,6 +91,7 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi private JButton myCopyButton; private JButton myDeleteButton; private JButton myResetToDefault; + private JCheckBox myNonEnglishKeyboardSupportOption; private JLabel myBaseKeymapLabel; @@ -233,7 +234,12 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi final JPanel panel = new JPanel(); panel.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 0)); panel.setLayout(new GridBagLayout()); - myCopyButton = new JButton(KeyMapBundle.message("copy.keymap.button")); + myCopyButton = new JButton(new AbstractAction(KeyMapBundle.message("copy.keymap.button")) { + @Override + public void actionPerformed(ActionEvent e) { + copyKeymap(); + } + }); Insets insets = new Insets(2, 2, 2, 2); myCopyButton.setMargin(insets); final GridBagConstraints gc = new GridBagConstraints(GridBagConstraints.RELATIVE, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 0, 0), 0, 0); @@ -241,19 +247,28 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi myResetToDefault = new JButton(CommonBundle.message("button.reset")); myResetToDefault.setMargin(insets); panel.add(myResetToDefault, gc); - myDeleteButton = new JButton(KeyMapBundle.message("delete.keymap.button")); + myDeleteButton = new JButton(new AbstractAction(KeyMapBundle.message("delete.keymap.button")) { + @Override + public void actionPerformed(ActionEvent e) { + deleteKeymap(); + } + }); myDeleteButton.setMargin(insets); gc.weightx = 1; panel.add(myDeleteButton, gc); - - myCopyButton.addActionListener( - new ActionListener() { + IdeFrame ideFrame = IdeFocusManager.getGlobalInstance().getLastFocusedFrame(); + if (ideFrame != null && KeyboardSettingsExternalizable.isSupportedKeyboardLayout( ideFrame.getComponent())) + { + String displayLanguage = ideFrame.getComponent().getInputContext().getLocale().getDisplayLanguage(); + myNonEnglishKeyboardSupportOption = new JCheckBox(new AbstractAction(displayLanguage + " " + KeyMapBundle.message("use.non.english.keyboard.layout.support")) { @Override - public void actionPerformed(@NotNull ActionEvent e) { - copyKeymap(); + public void actionPerformed(ActionEvent e) { + KeyboardSettingsExternalizable.getInstance().setNonEnglishKeyboardSupportEnabled(myNonEnglishKeyboardSupportOption.isSelected()); } - } - ); + }); + myNonEnglishKeyboardSupportOption.setSelected(KeyboardSettingsExternalizable.getInstance().isNonEnglishKeyboardSupportEnabled()); + panel.add(myNonEnglishKeyboardSupportOption, gc); + } myResetToDefault.addActionListener(new ActionListener() { @Override @@ -262,16 +277,6 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi } }); - - myDeleteButton.addActionListener( - new ActionListener() { - @Override - public void actionPerformed(@NotNull ActionEvent e) { - deleteKeymap(); - } - } - ); - return panel; } @@ -790,6 +795,12 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi @Override public void reset() { + + if (myNonEnglishKeyboardSupportOption != null) { + KeyboardSettingsExternalizable.getInstance().setNonEnglishKeyboardSupportEnabled(false); + myNonEnglishKeyboardSupportOption.setSelected(KeyboardSettingsExternalizable.getInstance().isNonEnglishKeyboardSupportEnabled()); + } + myKeymapListModel.removeAllElements(); KeymapManagerEx keymapManager = KeymapManagerEx.getInstanceEx(); Keymap[] keymaps = keymapManager.getAllKeymaps(); diff --git a/platform/platform-resources-en/src/messages/KeyMapBundle.properties b/platform/platform-resources-en/src/messages/KeyMapBundle.properties index af1b161b85df..9b7101d48621 100644 --- a/platform/platform-resources-en/src/messages/KeyMapBundle.properties +++ b/platform/platform-resources-en/src/messages/KeyMapBundle.properties @@ -46,6 +46,7 @@ remove.keymap.label=Remo&ve unnamed.list.display.name=unnamed copy.keymap.button=&Copy delete.keymap.button=De&lete +use.non.english.keyboard.layout.support=la&yout support parent.keymap.label=Parent keymap: disable.mnemonic.in.menu.check.box=Disable mnemonics in &menu diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index b327ce02bb15..5354e1af2984 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -292,6 +292,7 @@ serviceImplementation="com.intellij.openapi.actionSystem.impl.AbbreviationManagerImpl"/> +