diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeyboardShortcutDialog.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeyboardShortcutDialog.java index b08cf0fdd087..e00bdf6f7f0c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeyboardShortcutDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeyboardShortcutDialog.java @@ -15,260 +15,64 @@ */ package com.intellij.openapi.keymap.impl.ui; - -import com.intellij.ide.DataManager; -import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.KeyboardShortcut; -import com.intellij.openapi.actionSystem.ex.QuickList; -import com.intellij.openapi.help.HelpManager; import com.intellij.openapi.keymap.KeyMapBundle; import com.intellij.openapi.keymap.Keymap; -import com.intellij.openapi.keymap.KeymapUtil; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy; -import com.intellij.ui.IdeBorderFactory; -import com.intellij.ui.JBColor; -import com.intellij.ui.ScrollPaneFactory; -import com.intellij.util.ArrayUtil; import com.intellij.util.ui.JBUI; -import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import javax.swing.*; -import javax.swing.border.EmptyBorder; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.Map; -import java.util.Set; +import java.awt.BorderLayout; +import java.awt.Component; +import java.util.Collection; +import javax.swing.JComponent; +import javax.swing.JPanel; -public class KeyboardShortcutDialog extends DialogWrapper { - private StrokePanel myFirstStrokePanel; - private StrokePanel mySecondStrokePanel; - private final JCheckBox myEnableSecondKeystroke; - private final JLabel myKeystrokePreview; - private final JTextArea myConflictInfoArea; - private Keymap myKeymap; - private final String myActionId; - private final Group myMainGroup; +/** + * @author Sergey.Malenkov + */ +final class KeyboardShortcutDialog extends ShortcutDialog { + private final JComponent myPreferredFocusedComponent; + + KeyboardShortcutDialog(Component parent) { + super(parent, "keyboard.shortcut.dialog.title", new KeyboardShortcutPanel(new BorderLayout())); + + KeyboardShortcutPanel panel = (KeyboardShortcutPanel)myShortcutPanel; + myPreferredFocusedComponent = panel.myFirstStroke; + + JPanel inner = new JPanel(new BorderLayout()); + inner.add(BorderLayout.CENTER, panel.mySecondStroke); + inner.add(BorderLayout.WEST, panel.mySecondStrokeEnable); + panel.add(BorderLayout.NORTH, panel.myFirstStroke); + panel.add(BorderLayout.SOUTH, inner); + panel.setBorder(JBUI.Borders.empty(0, 10)); + panel.mySecondStrokeEnable.setSelected(true); + panel.mySecondStrokeEnable.setText(KeyMapBundle.message("dialog.enable.second.stroke.checkbox")); - public KeyboardShortcutDialog(Component component, String actionId, final QuickList[] quickLists) { - super(component, true); - setTitle(KeyMapBundle.message("keyboard.shortcut.dialog.title")); - myActionId = actionId; - final Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(component)); - myMainGroup = ActionsTreeUtil.createMainGroup(project, myKeymap, quickLists, null, false, null); //without current filter - myEnableSecondKeystroke = new JCheckBox(); - UIUtil.applyStyle(UIUtil.ComponentStyle.SMALL, myEnableSecondKeystroke); - myEnableSecondKeystroke.setBorder(new EmptyBorder(4, 0, 0, 2)); - myEnableSecondKeystroke.setFocusable(false); - myKeystrokePreview = new JLabel(" "); - myConflictInfoArea = new JTextArea(""); - myConflictInfoArea.setFocusable(false); init(); } - @NotNull - protected Action[] createActions(){ - return new Action[]{getOKAction(),getCancelAction(),getHelpAction()}; + @Override + protected String getHelpId() { + return "preferences.keymap.shortcut"; } - protected JComponent createCenterPanel() { - JPanel panel = new JPanel(new GridBagLayout()); - - // First stroke - - myFirstStrokePanel = new StrokePanel(KeyMapBundle.message("first.stroke.panel.title")); - panel.add( - myFirstStrokePanel, - new GridBagConstraints(0,0,2,1,1,0,GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0) - ); - - // Second stroke panel - - panel.add( - myEnableSecondKeystroke, - new GridBagConstraints(0,1,1,1,0,0,GridBagConstraints.NORTHWEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0) - ); - - mySecondStrokePanel = new StrokePanel(KeyMapBundle.message("second.stroke.panel.title")); - panel.add( - mySecondStrokePanel, - new GridBagConstraints(1,1,1,1,1,0,GridBagConstraints.NORTHWEST,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0) - ); - - // Shortcut preview - - JPanel previewPanel = new JPanel(new BorderLayout()); - previewPanel.setBorder(IdeBorderFactory.createTitledBorder(KeyMapBundle.message("shortcut.preview.ide.border.factory.title"), true)); - previewPanel.add(myKeystrokePreview); - panel.add( - previewPanel, - new GridBagConstraints(0,2,2,1,1,0,GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0) - ); - - // Conflicts - - JPanel conflictsPanel = new JPanel(new BorderLayout()); - conflictsPanel.setBorder(IdeBorderFactory.createTitledBorder(KeyMapBundle.message("conflicts.ide.border.factory.title"), - true)); - myConflictInfoArea.setEditable(false); - myConflictInfoArea.setBackground(panel.getBackground()); - myConflictInfoArea.setLineWrap(true); - myConflictInfoArea.setWrapStyleWord(true); - final JScrollPane conflictInfoScroll = ScrollPaneFactory.createScrollPane(myConflictInfoArea); - conflictInfoScroll.setPreferredSize(JBUI.size(260, 60)); - conflictInfoScroll.setBorder(null); - conflictsPanel.add(conflictInfoScroll); - panel.add( - conflictsPanel, - new GridBagConstraints(0,3,2,1,1,1,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0) - ); - - myEnableSecondKeystroke.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleSecondKey(); - updateCurrentKeyStrokeInfo(); - - /** TODO[anton]???? */ - if (myEnableSecondKeystroke.isSelected()) { - mySecondStrokePanel.getShortcutTextField().requestFocus(); - } - else { - myFirstStrokePanel.getShortcutTextField().requestFocus(); - } - } - }); - return panel; + @Override + public JComponent getPreferredFocusedComponent() { + return myPreferredFocusedComponent; } - public JComponent getPreferredFocusedComponent(){ - return IdeFocusTraversalPolicy.getPreferredFocusedComponent(myFirstStrokePanel); + @Override + KeyboardShortcut toShortcut(Object value) { + return value instanceof KeyboardShortcut ? (KeyboardShortcut)value : null; } - public void setData(Keymap keymap, KeyboardShortcut shortcut) { - myKeymap = keymap; - myEnableSecondKeystroke.setSelected(false); - if (shortcut != null) { - myFirstStrokePanel.getShortcutTextField().setKeyStroke(shortcut.getFirstKeyStroke()); - if (shortcut.getSecondKeyStroke() != null) { - myEnableSecondKeystroke.setSelected(true); - mySecondStrokePanel.getShortcutTextField().setKeyStroke(shortcut.getSecondKeyStroke()); - } - } - handleSecondKey(); - updateCurrentKeyStrokeInfo(); + @Override + Collection getConflicts(KeyboardShortcut shortcut, String actionId, Keymap keymap) { + return keymap.getConflicts(actionId, shortcut).keySet(); } - private void updateCurrentKeyStrokeInfo() { - if (myConflictInfoArea == null || myKeystrokePreview == null){ - return; - } - - myConflictInfoArea.setText(null); - myKeystrokePreview.setText(" "); - - if (myKeymap == null){ - return; - } - - KeyboardShortcut keyboardShortcut = getKeyboardShortcut(); - if (keyboardShortcut == null){ - return; - } - - String strokeText = getTextByKeyStroke(keyboardShortcut.getFirstKeyStroke()); - String suffixText = getTextByKeyStroke(keyboardShortcut.getSecondKeyStroke()); - if(suffixText != null && suffixText.length() > 0) { - strokeText += ',' + suffixText; - } - myKeystrokePreview.setText(strokeText); - - StringBuilder buffer = new StringBuilder(); - - Map> conflicts = myKeymap.getConflicts(myActionId, keyboardShortcut); - - Set keys = conflicts.keySet(); - String[] actionIds = ArrayUtil.toStringArray(keys); - boolean loaded = true; - for (String actionId : actionIds) { - String actionPath = myMainGroup.getActionQualifiedPath(actionId); - if (actionPath == null) { - loaded = false; - } - if (buffer.length() > 1) { - buffer.append('\n'); - } - buffer.append('['); - buffer.append(actionPath != null ? actionPath : actionId); - buffer.append(']'); - } - - if (buffer.length() == 0) { - myConflictInfoArea.setForeground(UIUtil.getTextAreaForeground()); - myConflictInfoArea.setText(KeyMapBundle.message("no.conflict.info.message")); - } - else { - myConflictInfoArea.setForeground(JBColor.RED); - if (loaded) { - myConflictInfoArea.setText(KeyMapBundle.message("assigned.to.info.message", buffer.toString())); - } - else { - myConflictInfoArea.setText("Assigned to " + buffer.toString() + " which is now not loaded but may be loaded later"); - } - } - } - - private void handleSecondKey() { - mySecondStrokePanel.setEnabled(myEnableSecondKeystroke.isSelected()); - } - - @Nullable - public KeyboardShortcut getKeyboardShortcut() { - KeyStroke firstStroke = myFirstStrokePanel.getKeyStroke(); - return firstStroke == null ? null : new KeyboardShortcut(firstStroke, myEnableSecondKeystroke.isSelected() ? mySecondStrokePanel.getKeyStroke() : null); - } - - static String getTextByKeyStroke(KeyStroke keyStroke) { - if(keyStroke == null) { - return ""; - } - return KeymapUtil.getKeystrokeText(keyStroke); - } - - protected void doHelpAction() { - HelpManager.getInstance().invokeHelp("preferences.keymap.shortcut"); - } - - private class StrokePanel extends JPanel { - private final ShortcutTextField myShortcutTextField; - - public StrokePanel(String borderText) { - setLayout(new BorderLayout()); - setBorder(IdeBorderFactory.createTitledBorder(borderText, false)); - - myShortcutTextField = new ShortcutTextField(){ - protected void updateCurrentKeyStrokeInfo() { - KeyboardShortcutDialog.this.updateCurrentKeyStrokeInfo(); - } - }; - add(myShortcutTextField); - } - - public ShortcutTextField getShortcutTextField() { - return myShortcutTextField; - } - - public void setEnabled(boolean state) { - myShortcutTextField.setEnabled(state); - repaint(); - } - - public KeyStroke getKeyStroke() { - return myShortcutTextField.getKeyStroke(); - } + @Override + String getActionPath(String actionId) { + String actionPath = super.getActionPath(actionId); + return actionPath != null ? actionPath : actionId; } } diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeyboardShortcutPanel.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeyboardShortcutPanel.java index 163b3975ca3a..982689937329 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeyboardShortcutPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeyboardShortcutPanel.java @@ -16,7 +16,6 @@ package com.intellij.openapi.keymap.impl.ui; import com.intellij.openapi.actionSystem.KeyboardShortcut; -import com.intellij.openapi.actionSystem.Shortcut; import java.awt.LayoutManager; import java.awt.event.ItemEvent; @@ -24,19 +23,16 @@ import java.awt.event.ItemListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.JCheckBox; -import javax.swing.JPanel; import javax.swing.KeyStroke; /** * @author Sergey.Malenkov */ -final class KeyboardShortcutPanel extends JPanel { +final class KeyboardShortcutPanel extends ShortcutPanel { final ShortcutTextField myFirstStroke = new ShortcutTextField(); final ShortcutTextField mySecondStroke = new ShortcutTextField(); final JCheckBox mySecondStrokeEnable = new JCheckBox(); - private KeyboardShortcut myShortcut; - private final ItemListener myItemListener = new ItemListener() { @Override public void itemStateChanged(ItemEvent event) { @@ -50,37 +46,35 @@ final class KeyboardShortcutPanel extends JPanel { private final PropertyChangeListener myPropertyListener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent event) { - setShortcut(newShortcut()); - if (null == myFirstStroke.getKeyStroke()) { - myFirstStroke.requestFocus(); + if (KeyboardShortcutPanel.this != event.getSource()) { + setShortcut(newShortcut()); + if (null == myFirstStroke.getKeyStroke()) { + myFirstStroke.requestFocus(); + } + else if (null == mySecondStroke.getKeyStroke() && mySecondStrokeEnable.isSelected()) { + mySecondStroke.requestFocus(); + } } - else if (null == mySecondStroke.getKeyStroke() && mySecondStrokeEnable.isSelected()) { - mySecondStroke.requestFocus(); + else if (event.getNewValue() instanceof KeyboardShortcut) { + KeyboardShortcut shortcut = (KeyboardShortcut)event.getNewValue(); + myFirstStroke.setKeyStroke(shortcut.getFirstKeyStroke()); + mySecondStroke.setKeyStroke(shortcut.getSecondKeyStroke()); + } + else { + myFirstStroke.setKeyStroke(null); + mySecondStroke.setKeyStroke(null); } } }; KeyboardShortcutPanel(LayoutManager layout) { super(layout); + addPropertyChangeListener("shortcut", myPropertyListener); myFirstStroke.addPropertyChangeListener("keyStroke", myPropertyListener); mySecondStroke.addPropertyChangeListener("keyStroke", myPropertyListener); mySecondStrokeEnable.addItemListener(myItemListener); } - KeyboardShortcut getShortcut() { - return myShortcut; - } - - void setShortcut(KeyboardShortcut shortcut) { - Shortcut old = myShortcut; - if (old == null || !old.equals(shortcut)) { - myShortcut = shortcut; - myFirstStroke.setKeyStroke(shortcut == null ? null : shortcut.getFirstKeyStroke()); - mySecondStroke.setKeyStroke(shortcut == null ? null : shortcut.getSecondKeyStroke()); - firePropertyChange("shortcut", old, shortcut); - } - } - private KeyboardShortcut newShortcut() { KeyStroke key = myFirstStroke.getKeyStroke(); return key == null ? null : new KeyboardShortcut(key, !mySecondStrokeEnable.isSelected() ? null : mySecondStroke.getKeyStroke()); 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 eea7a96dab05..3083d4f6508b 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 @@ -36,7 +36,6 @@ import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.project.DumbAwareAction; -import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.ListPopup; @@ -479,13 +478,8 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi @NotNull Keymap keymap, @NotNull Component parent, @NotNull QuickList[] quickLists) { - KeyboardShortcutDialog dialog = new KeyboardShortcutDialog(parent, actionId, quickLists); - dialog.setData(keymap, shortcut instanceof KeyboardShortcut ? (KeyboardShortcut)shortcut : null); - if (!dialog.showAndGet()) { - return; - } - - KeyboardShortcut keyboardShortcut = dialog.getKeyboardShortcut(); + KeyboardShortcutDialog dialog = new KeyboardShortcutDialog(parent); + KeyboardShortcut keyboardShortcut = dialog.showAndGet(shortcut, actionId, keymap, quickLists); if (keyboardShortcut == null) { return; } @@ -535,22 +529,8 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi Keymap keymap = createKeymapCopyIfNeeded(); - MouseShortcut mouseShortcut = shortcut instanceof MouseShortcut ? (MouseShortcut)shortcut : null; - Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(this)); - MouseShortcutDialog dialog = new MouseShortcutDialog( - this, - mouseShortcut, - keymap, - actionId, - ActionsTreeUtil.createMainGroup(project, keymap, myQuickLists, null, true, null), - restrictions - ); - if (!dialog.showAndGet()) { - return; - } - - mouseShortcut = dialog.getMouseShortcut(); - + MouseShortcutDialog dialog = new MouseShortcutDialog(this, restrictions.allowMouseDoubleClick); + MouseShortcut mouseShortcut = dialog.showAndGet(shortcut, actionId, keymap, myQuickLists); if (mouseShortcut == null) { return; } diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/MouseShortcutDialog.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/MouseShortcutDialog.java index 2de4bdf5f3eb..fe0e21de9a4c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/MouseShortcutDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/MouseShortcutDialog.java @@ -17,275 +17,68 @@ package com.intellij.openapi.keymap.impl.ui; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.MouseShortcut; -import com.intellij.openapi.actionSystem.Shortcut; import com.intellij.openapi.keymap.KeyMapBundle; import com.intellij.openapi.keymap.Keymap; import com.intellij.openapi.keymap.KeymapUtil; -import com.intellij.openapi.keymap.impl.ShortcutRestrictions; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.ui.IdeBorderFactory; -import com.intellij.ui.JBColor; -import com.intellij.ui.ScrollPaneFactory; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; -import org.intellij.lang.annotations.JdkConstants; -import org.jetbrains.annotations.NotNull; -import javax.swing.*; -import java.awt.*; -import java.awt.event.*; +import java.awt.BorderLayout; +import java.awt.Component; +import java.util.Arrays; +import java.util.Collection; +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.SwingConstants; /** * @author Vladimir Kondratyev + * @author Sergey.Malenkov */ -class MouseShortcutDialog extends DialogWrapper{ - private final Keymap myKeymap; - private final String myActionId; - private final Group myMainGroup; +final class MouseShortcutDialog extends ShortcutDialog { + private final JLabel myText = new JLabel("", SwingConstants.CENTER); - private final JRadioButton myRbSingleClick; - private final JRadioButton myRbDoubleClick; - private final JLabel myLblPreview; - private final JLabel myClickPad; - private final JTextArea myTarConflicts; + MouseShortcutDialog(Component component, boolean allowDoubleClick) { + super(component, "mouse.shortcut.dialog.title", new MouseShortcutPanel(allowDoubleClick)); - private final MouseShortcutConsumer myShortcutConsumer; - - private int myButton; - @JdkConstants.InputEventMask private int myModifiers; - - /** - * @param shortcut dialog will be initialized with this shortcut. It can be null - * if dialog is used to create new mouse shortcut. - */ - public MouseShortcutDialog( - JComponent parentComponent, - MouseShortcut shortcut, - @NotNull Keymap keymap, - @NotNull String actiondId, - @NotNull Group mainGroup, - @NotNull ShortcutRestrictions restrictions - ){ - super(parentComponent,true); - setTitle(KeyMapBundle.message("mouse.shortcut.dialog.title")); - - myKeymap=keymap; - myActionId=actiondId; - myMainGroup=mainGroup; - - myRbSingleClick=new JRadioButton(KeyMapBundle.message("mouse.shortcut.dialog.single.click.radio")); - myRbDoubleClick=new JRadioButton(KeyMapBundle.message("mouse.shortcut.dialog.double.click.radio")); - ButtonGroup buttonGroup=new ButtonGroup(); - buttonGroup.add(myRbSingleClick); - buttonGroup.add(myRbDoubleClick); - - myLblPreview=new JLabel(" "); - - myTarConflicts=new JTextArea(); - myTarConflicts.setFocusable(false); - myTarConflicts.setEditable(false); - myTarConflicts.setBackground(UIUtil.getPanelBackground()); - myTarConflicts.setLineWrap(true); - myTarConflicts.setWrapStyleWord(true); - - if(shortcut!=null){ - if(shortcut.getClickCount()==1){ - myRbSingleClick.setSelected(true); - }else{ - myRbDoubleClick.setSelected(true); - } - myButton=shortcut.getButton(); - myModifiers=shortcut.getModifiers(); - }else{ - myRbSingleClick.setSelected(true); - myButton=-1; - myModifiers=-1; - } - - myRbDoubleClick.setEnabled(restrictions.allowMouseDoubleClick); - - updatePreviewAndConflicts(); - - myClickPad = new JLabel( - KeyMapBundle.message("mouse.shortcut.label"), - AllIcons.General.Mouse, SwingConstants.LEADING - ); - myShortcutConsumer = new MouseShortcutConsumer(shortcut) { - @Override - public void consume(MouseShortcut shortcut) { - myButton = shortcut.getButton(); - myModifiers = shortcut.getModifiers(); - updatePreviewAndConflicts(); - } - }; - myClickPad.addHierarchyListener(myShortcutConsumer); + myShortcutPanel.add(BorderLayout.NORTH, new JLabel(AllIcons.General.Mouse, SwingConstants.CENTER)); + myShortcutPanel.add(BorderLayout.CENTER, myText); + myShortcutPanel.setBorder(BorderFactory.createCompoundBorder( + JBUI.Borders.customLine(MouseShortcutPanel.BORDER, 1, 0, 1, 0), + JBUI.Borders.empty(20) + )); init(); } - /** - * @return created/edited shortcut. Returns null if shortcut is invalid. - */ - public MouseShortcut getMouseShortcut(){ - if (myButton > 3 && myButton != MouseShortcut.BUTTON_WHEEL_UP && myButton != MouseShortcut.BUTTON_WHEEL_DOWN && getClickCount() == 2) { - return null; - } - - if(myButton!=-1 && myModifiers!=-1){ - return new MouseShortcut(myButton,myModifiers,getClickCount()); - }else{ - return null; - } - } - @Override protected String getHelpId() { return "preferences.mouse.shortcut"; } - protected JComponent createCenterPanel(){ - JPanel panel=new JPanel(new GridBagLayout()); - - // Single/Double click - - JPanel clickCountPanel=new JPanel(new GridBagLayout()); - clickCountPanel.setBorder(IdeBorderFactory.createTitledBorder( - KeyMapBundle.message("mouse.shortcut.dialog.click.count.border"), true)); - panel.add( - clickCountPanel, - new GridBagConstraints(0,0,1,1,1,0,GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0) - ); - clickCountPanel.add( - myRbSingleClick, - new GridBagConstraints(0,0,1,1,1,0,GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,0,0,10),0,0) - ); - clickCountPanel.add( - myRbDoubleClick, - new GridBagConstraints(1,0,1,1,1,0,GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0) - ); - - ActionListener listener=new ActionListener(){ - public void actionPerformed(ActionEvent e){ - updatePreviewAndConflicts(); - } - }; - myRbSingleClick.addActionListener(listener); - myRbDoubleClick.addActionListener(listener); - - // Click pad - - panel.add( - myClickPad, - new GridBagConstraints(0,1,1,1,1,0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,4,0),0,0) - ); - myClickPad.setBorder(BorderFactory.createCompoundBorder( - IdeBorderFactory.createTitledBorder(KeyMapBundle.message("mouse.shortcut.dialog.click.pad.border"), true), - JBUI.Borders.empty(20, 0, 20, 20))); - - // Shortcut preview - - JPanel previewPanel=new JPanel(new GridBagLayout()); - previewPanel.setBorder(IdeBorderFactory.createTitledBorder( - KeyMapBundle.message("mouse.shortcut.dialog.shortcut.preview.border"), true)); - panel.add( - previewPanel, - new GridBagConstraints(0,2,1,1,1,0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,4,0),0,0) - ); - previewPanel.add( - myLblPreview, - new GridBagConstraints(0,0,1,1,1,1,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(2,2,2,2),0,0) - ); - - // Conflicts panel - - JPanel conflictsPanel=new JPanel(new GridBagLayout()); - conflictsPanel.setBorder(IdeBorderFactory.createTitledBorder( - KeyMapBundle.message("mouse.shortcut.dialog.conflicts.border"), true)); - panel.add( - conflictsPanel, - new GridBagConstraints(0,3,1,1,1,1,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0) - ); - myTarConflicts.setPreferredSize(JBUI.size(260,60)); - JScrollPane scrollPane= ScrollPaneFactory.createScrollPane(myTarConflicts); - scrollPane.setBorder(null); - conflictsPanel.add( - scrollPane, - new GridBagConstraints(0,0,1,1,1,1,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0) - ); - - return panel; + @Override + MouseShortcut toShortcut(Object value) { + return value instanceof MouseShortcut ? (MouseShortcut)value : null; } - private int getClickCount() { - return myRbSingleClick.isSelected() ? 1 : 2; - } - /** - * Updates all UI controls - */ - private void updatePreviewAndConflicts(){ - if(myButton==-1||myModifiers==-1){ - return; - } - - myTarConflicts.setText(null); - - // Set text into preview area - - // empty string should have same height - myLblPreview.setText(KeymapUtil.getMouseShortcutText(myButton,myModifiers,getClickCount()) + " "); - - // Detect conflicts - - final MouseShortcut mouseShortcut=new MouseShortcut(myButton,myModifiers,getClickCount()); - - if (myButton > 3 && getClickCount() == 2) { - myTarConflicts.setForeground(JBColor.RED); - myTarConflicts.setText(KeyMapBundle.message("mouse.shortcut.dialog.side.buttons.with.double.click", myButton)); - return; - } - - StringBuilder buffer = new StringBuilder(); - String[] actionIds = myKeymap.getActionIds(mouseShortcut); - for (String actionId : actionIds) { - if (actionId.equals(myActionId)) { - continue; - } - - String actionPath = myMainGroup.getActionQualifiedPath(actionId); - // actionPath == null for editor actions having corresponding $-actions - if (actionPath == null) { - continue; - } - - Shortcut[] shortcuts = myKeymap.getShortcuts(actionId); - for (Shortcut shortcut1 : shortcuts) { - if (!(shortcut1 instanceof MouseShortcut)) { - continue; - } - - MouseShortcut shortcut = (MouseShortcut)shortcut1; - - if (shortcut.getButton() != mouseShortcut.getButton() || shortcut.getModifiers() != mouseShortcut.getModifiers()) { - continue; - } - - if (buffer.length() > 1) { - buffer.append('\n'); - } - buffer.append('['); - buffer.append(actionPath); - buffer.append(']'); - break; - } - } - - if (buffer.length() == 0) { - myTarConflicts.setForeground(UIUtil.getTextAreaForeground()); - myTarConflicts.setText(KeyMapBundle.message("mouse.shortcut.dialog.no.conflicts.area")); + @Override + void setShortcut(MouseShortcut shortcut) { + super.setShortcut(shortcut); + if (shortcut == null) { + myText.setForeground(MouseShortcutPanel.FOREGROUND); + myText.setText(KeyMapBundle.message("dialog.mouse.pad.default.text")); } else { - myTarConflicts.setForeground(JBColor.RED); - myTarConflicts.setText(KeyMapBundle.message("mouse.shortcut.dialog.assigned.to.area", buffer.toString())); + myText.setForeground(UIUtil.getLabelForeground()); + myText.setText(KeyMapBundle.message("dialog.mouse.pad.shortcut.text", KeymapUtil.getMouseShortcutText( + shortcut.getButton(), + shortcut.getModifiers(), + shortcut.getClickCount()))); } } + + @Override + Collection getConflicts(MouseShortcut shortcut, String actionId, Keymap keymap) { + return Arrays.asList(keymap.getActionIds(shortcut)); + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/MouseShortcutPanel.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/MouseShortcutPanel.java index 0e0e6eeeebd2..a407bb780f65 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/MouseShortcutPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/MouseShortcutPanel.java @@ -22,18 +22,16 @@ import java.awt.BorderLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; -import javax.swing.JPanel; /** * @author Sergey.Malenkov */ -final class MouseShortcutPanel extends JPanel { +final class MouseShortcutPanel extends ShortcutPanel { static final JBColor FOREGROUND = new JBColor(0x8C8C8C, 0x8C8C8C); static final JBColor BACKGROUND = new JBColor(0xF5F5F5, 0x4B4F52); static final JBColor BORDER = new JBColor(0xDEDEDE, 0x383B3D); - private MouseShortcut myShortcut; - + private final int myClickCount; private final MouseAdapter myMouseListener = new MouseAdapter() { @Override public void mouseWheelMoved(MouseWheelEvent event) { @@ -46,35 +44,26 @@ final class MouseShortcutPanel extends JPanel { int button = MouseShortcut.getButton(event); int clickCount = event instanceof MouseWheelEvent ? 1 : event.getClickCount(); - if (0 <= button && clickCount < 3) { + if (0 <= button && clickCount <= myClickCount) { int modifiers = event.getModifiersEx(); - if (myShortcut == null - || button != myShortcut.getButton() - || modifiers != myShortcut.getModifiers() - || clickCount != myShortcut.getClickCount()) { - setShortcut(new MouseShortcut(button, modifiers, clickCount)); - } + setShortcut(new MouseShortcut(button, modifiers, clickCount)); } } }; - MouseShortcutPanel() { + MouseShortcutPanel(boolean allowDoubleClick) { super(new BorderLayout()); + myClickCount = allowDoubleClick ? 2 : 1; addMouseListener(myMouseListener); addMouseWheelListener(myMouseListener); setBackground(BACKGROUND); setOpaque(true); } - MouseShortcut getShortcut() { - return myShortcut; - } - void setShortcut(MouseShortcut shortcut) { - MouseShortcut old = myShortcut; + MouseShortcut old = getShortcut(); if (old != null || shortcut != null) { - myShortcut = shortcut; - firePropertyChange("shortcut", old, shortcut); + super.setShortcut(shortcut); } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutDialog.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutDialog.java new file mode 100644 index 000000000000..c3ade8b94c5e --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutDialog.java @@ -0,0 +1,185 @@ +/* + * 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.impl.ui; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.DataManager; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.Shortcut; +import com.intellij.openapi.actionSystem.ex.QuickList; +import com.intellij.openapi.keymap.KeyMapBundle; +import com.intellij.openapi.keymap.Keymap; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.ui.ScrollPaneFactory; +import com.intellij.ui.SimpleColoredComponent; +import com.intellij.ui.SimpleTextAttributes; +import com.intellij.ui.components.GradientViewport; +import com.intellij.ui.components.JBPanel; +import com.intellij.ui.components.panels.VerticalLayout; +import com.intellij.util.ui.ButtonlessScrollBarUI; +import com.intellij.util.ui.JBUI; +import org.jetbrains.annotations.Nullable; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Collection; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.ScrollPaneConstants; +import javax.swing.SwingConstants; +import javax.swing.border.Border; + +/** + * @author Sergey.Malenkov + */ +abstract class ShortcutDialog extends DialogWrapper { + private final SimpleColoredComponent myAction = new SimpleColoredComponent(); + private final JBPanel myConflictsContainer = new JBPanel(new VerticalLayout(0)); + private final JBPanel myConflictsPanel = new JBPanel(new BorderLayout()) + .withBorder(JBUI.Borders.empty(5, 10, 0, 10)) + .withPreferredHeight(64) + .withMinimumHeight(64); + + protected final ShortcutPanel myShortcutPanel; + private final Project myProject; + private String myActionId; + private Keymap myKeymap; + private Group myGroup; + + ShortcutDialog(Component parent, String title, ShortcutPanel panel) { + super(parent, true); + myShortcutPanel = panel; + myProject = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(parent)); + setTitle(KeyMapBundle.message(title)); + } + + String getActionPath(String actionId) { + return myGroup == null ? null : myGroup.getActionQualifiedPath(actionId); + } + + abstract Collection getConflicts(T shortcut, String actionId, Keymap keymap); + + abstract T toShortcut(Object value); + + void setShortcut(T shortcut) { + if (!equal(shortcut, myShortcutPanel.getShortcut())) { + myShortcutPanel.setShortcut(shortcut); + } + myConflictsContainer.removeAll(); + if (shortcut != null) { + for (String id : getConflicts(shortcut, myActionId, myKeymap)) { + String path = id.equals(myActionId) ? null : getActionPath(id); + if (path != null) { + SimpleColoredComponent component = new SimpleColoredComponent(); + fill(component, id, path); + myConflictsContainer.add(VerticalLayout.TOP, component); + } + } + myConflictsPanel.revalidate(); + } + myConflictsPanel.setVisible(0 < myConflictsContainer.getComponentCount()); + } + + T showAndGet(Shortcut shortcut, String id, Keymap keymap, QuickList... lists) { + myActionId = id; + myKeymap = keymap; + myGroup = ActionsTreeUtil.createMainGroup(myProject, keymap, lists, null, false, null); + fill(myAction, id, getActionPath(id)); + setShortcut(toShortcut(shortcut)); + return showAndGet() ? myShortcutPanel.getShortcut() : null; + } + + @Nullable + @Override + protected Border createContentPaneBorder() { + return JBUI.Borders.empty(); + } + + @Nullable + @Override + protected JComponent createSouthPanel() { + JComponent panel = super.createSouthPanel(); + if (panel != null) { + panel.setBorder(JBUI.Borders.empty(8, 12)); + } + return panel; + } + + @Nullable + @Override + protected JComponent createNorthPanel() { + myAction.setIpad(JBUI.insets(10, 10, 5, 10)); + myShortcutPanel.addPropertyChangeListener("shortcut", new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent event) { + setShortcut(toShortcut(event.getNewValue())); + } + }); + JBPanel result = new JBPanel(new BorderLayout()).withPreferredWidth(300).withMinimumWidth(200); + result.add(BorderLayout.NORTH, myAction); + result.add(BorderLayout.SOUTH, myShortcutPanel); + return result; + } + + @Override + protected JComponent createCenterPanel() { + JLabel icon = new JLabel(AllIcons.General.BalloonWarning); + icon.setVerticalAlignment(SwingConstants.TOP); + + JLabel label = new JLabel(KeyMapBundle.message("dialog.conflicts.text")); + label.setBorder(JBUI.Borders.emptyLeft(2)); + + JScrollPane scroll = ScrollPaneFactory.createScrollPane(null, true); + scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + scroll.setViewport(new GradientViewport(myConflictsContainer, JBUI.insets(5), false)); + scroll.getVerticalScrollBar().setUI(ButtonlessScrollBarUI.createTransparent()); + scroll.getVerticalScrollBar().setUnitIncrement(JBUI.scale(10)); + + JBPanel panel = new JBPanel(new BorderLayout()); + panel.add(BorderLayout.NORTH, label); + panel.add(BorderLayout.CENTER, scroll); + + myConflictsPanel.add(BorderLayout.WEST, icon); + myConflictsPanel.add(BorderLayout.CENTER, panel); + myConflictsContainer.setOpaque(false); + return myConflictsPanel; + } + + private static boolean equal(Shortcut newShortcut, Shortcut oldShortcut) { + return newShortcut == null ? oldShortcut == null : newShortcut.equals(oldShortcut); + } + + private static void fill(SimpleColoredComponent component, String id, String path) { + if (path == null) { + component.append(id, SimpleTextAttributes.REGULAR_ITALIC_ATTRIBUTES); + } + else { + int index = path.lastIndexOf(" | "); + if (index < 0) { + component.append(path, SimpleTextAttributes.REGULAR_ATTRIBUTES); + } + else { + component.append(path.substring(index + 3), SimpleTextAttributes.REGULAR_ATTRIBUTES); + component.append(" in ", SimpleTextAttributes.GRAYED_ATTRIBUTES); + component.append(path.substring(0, index), SimpleTextAttributes.GRAYED_ATTRIBUTES); + } + } + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutFilteringPanel.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutFilteringPanel.java index 6e3b199eade5..ccedfc13be04 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutFilteringPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutFilteringPanel.java @@ -40,7 +40,7 @@ import javax.swing.event.ChangeListener; */ final class ShortcutFilteringPanel extends JPanel { final KeyboardShortcutPanel myKeyboardPanel = new KeyboardShortcutPanel(new VerticalLayout(JBUI.scale(2))); - final MouseShortcutPanel myMousePanel = new MouseShortcutPanel(); + final MouseShortcutPanel myMousePanel = new MouseShortcutPanel(true); private Shortcut myShortcut; private JBPopup myPopup; diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutPanel.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutPanel.java new file mode 100644 index 000000000000..1cad3154f95b --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutPanel.java @@ -0,0 +1,42 @@ +/* + * 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.impl.ui; + +import com.intellij.openapi.actionSystem.Shortcut; + +import java.awt.LayoutManager; +import javax.swing.JPanel; + +/** + * @author Sergey.Malenkov + */ +class ShortcutPanel extends JPanel { + private T myShortcut; + + ShortcutPanel(LayoutManager layout) { + super(layout); + } + + T getShortcut() { + return myShortcut; + } + + void setShortcut(T shortcut) { + T old = myShortcut; + myShortcut = shortcut; + firePropertyChange("shortcut", old, shortcut); + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutTextField.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutTextField.java index b35a096fd51d..fa7f6787ac3f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutTextField.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutTextField.java @@ -31,10 +31,10 @@ import javax.swing.text.DefaultCaret; import java.awt.*; import java.awt.event.KeyEvent; -public class ShortcutTextField extends JTextField { +public final class ShortcutTextField extends JTextField { private KeyStroke myKeyStroke; - public ShortcutTextField() { + ShortcutTextField() { enableEvents(AWTEvent.KEY_EVENT_MASK); setFocusTraversalKeysEnabled(false); putClientProperty("JTextField.variant", "search"); @@ -62,21 +62,17 @@ public class ShortcutTextField extends JTextField { } } - public void setKeyStroke(KeyStroke keyStroke) { + void setKeyStroke(KeyStroke keyStroke) { KeyStroke old = myKeyStroke; if (old != null || keyStroke != null) { myKeyStroke = keyStroke; super.setText(KeymapUtil.getKeystrokeText(keyStroke)); setCaretPosition(0); - updateCurrentKeyStrokeInfo(); firePropertyChange("keyStroke", old, keyStroke); } } - protected void updateCurrentKeyStrokeInfo() { - } - - public KeyStroke getKeyStroke() { + KeyStroke getKeyStroke() { return myKeyStroke; } diff --git a/platform/platform-resources-en/src/messages/KeyMapBundle.properties b/platform/platform-resources-en/src/messages/KeyMapBundle.properties index 29986a28f522..010c44825ea7 100644 --- a/platform/platform-resources-en/src/messages/KeyMapBundle.properties +++ b/platform/platform-resources-en/src/messages/KeyMapBundle.properties @@ -96,6 +96,11 @@ mouse.wheel.rotate.down.shortcut.text={0}Wheel down configuration.all.keymaps.should.have.non.empty.names.error.message=All keymaps should have non empty names configuration.all.keymaps.should.have.unique.names.error.message=All keymaps should have unique names +dialog.enable.second.stroke.checkbox=Second stroke: +dialog.mouse.pad.default.text=
Enter a shortcut here:
single or double-click, scroll the wheel,
modify with Ctrl, Alt and Shift +dialog.mouse.pad.shortcut.text=

{0}

+dialog.conflicts.text=Already assigned to: + filter.clear.action.text=Clear Filtering filter.settings.popup.title=Find Shortcut filter.enable.second.stroke.checkbox=Second stroke diff --git a/platform/util/src/com/intellij/ui/components/JBPanel.java b/platform/util/src/com/intellij/ui/components/JBPanel.java index b265c961e496..fb0101033965 100644 --- a/platform/util/src/com/intellij/ui/components/JBPanel.java +++ b/platform/util/src/com/intellij/ui/components/JBPanel.java @@ -16,6 +16,7 @@ package com.intellij.ui.components; import com.intellij.util.ui.JBFont; +import com.intellij.util.ui.JBUI; import com.intellij.util.ui.components.JBComponent; import javax.swing.*; @@ -27,6 +28,12 @@ import java.awt.*; */ @SuppressWarnings("unchecked") public class JBPanel extends JPanel implements JBComponent { + private Integer myPreferredWidth; + private Integer myPreferredHeight; + private Integer myMaximumWidth; + private Integer myMaximumHeight; + private Integer myMinimumWidth; + private Integer myMinimumHeight; public JBPanel(LayoutManager layout, boolean isDoubleBuffered) { super(layout, isDoubleBuffered); @@ -67,4 +74,57 @@ public class JBPanel extends JPanel implements JBComponent setOpaque(true); return (T)this; } + + public T withPreferredWidth(int width) { + myPreferredWidth = width; + return (T)this; + } + + public T withPreferredHeight(int height) { + myPreferredHeight = height; + return (T)this; + } + + public T withMaximumWidth(int width) { + myMaximumWidth = width; + return (T)this; + } + + public T withMaximumHeight(int height) { + myMaximumHeight = height; + return (T)this; + } + + public T withMinimumWidth(int width) { + myMinimumWidth = width; + return (T)this; + } + + public T withMinimumHeight(int height) { + myMinimumHeight = height; + return (T)this; + } + + @Override + public Dimension getPreferredSize() { + return getSize(super.getPreferredSize(), myPreferredWidth, myPreferredHeight, isPreferredSizeSet()); + } + + @Override + public Dimension getMaximumSize() { + return getSize(super.getMaximumSize(), myMaximumWidth, myMaximumHeight, isMaximumSizeSet()); + } + + @Override + public Dimension getMinimumSize() { + return getSize(super.getMinimumSize(), myMinimumWidth, myMinimumHeight, isMinimumSizeSet()); + } + + private static Dimension getSize(Dimension size, Integer width, Integer height, boolean isSet) { + if (!isSet && size != null) { + if (width != null) size.width = JBUI.scale(width); + if (height != null) size.height = JBUI.scale(height); + } + return size; + } }