| /* |
| * Copyright 2000-2014 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.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.UIUtil; |
| import org.intellij.lang.annotations.JdkConstants; |
| import org.jetbrains.annotations.NotNull; |
| |
| import javax.swing.*; |
| import java.awt.*; |
| import java.awt.event.*; |
| |
| /** |
| * @author Vladimir Kondratyev |
| */ |
| class MouseShortcutDialog extends DialogWrapper{ |
| private final Keymap myKeymap; |
| private final String myActionId; |
| private final Group myMainGroup; |
| |
| private final JRadioButton myRbSingleClick; |
| private final JRadioButton myRbDoubleClick; |
| private final JLabel myLblPreview; |
| private final MyClickPad myClickPad; |
| private final JTextArea myTarConflicts; |
| |
| private int myButton; |
| @JdkConstants.InputEventMask private int myModifiers; |
| |
| /** |
| * @param shortcut dialog will be initialized with this <code>shortcut</code>. It can be <code>null</code> |
| * 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(" "); |
| |
| myClickPad=new MyClickPad(); |
| |
| 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(); |
| |
| init(); |
| } |
| |
| /** |
| * @return created/edited shortcut. Returns <code>null</code> if shortcut is invalid. |
| */ |
| public MouseShortcut getMouseShortcut(){ |
| if (myButton > 3 && 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 |
| |
| JPanel clickPadPanel=new JPanel(new BorderLayout()); |
| panel.add( |
| clickPadPanel, |
| new GridBagConstraints(0,1,1,1,1,0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,4,0),0,0) |
| ); |
| clickPadPanel.setBorder(IdeBorderFactory.createTitledBorder( |
| KeyMapBundle.message("mouse.shortcut.dialog.click.pad.border"), true)); |
| myClickPad.setPreferredSize(new Dimension(260,60)); |
| clickPadPanel.add(myClickPad,BorderLayout.CENTER); |
| |
| // 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(new Dimension(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; |
| } |
| |
| 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")); |
| } |
| else { |
| myTarConflicts.setForeground(JBColor.RED); |
| myTarConflicts.setText(KeyMapBundle.message("mouse.shortcut.dialog.assigned.to.area", buffer.toString())); |
| } |
| } |
| |
| private class MyClickPad extends JLabel{ |
| public MyClickPad(){ |
| super( |
| KeyMapBundle.message("mouse.shortcut.label"), |
| AllIcons.General.Mouse, SwingConstants.CENTER |
| ); |
| // It's very imporatant that MouseListener is added to the Dialog. If you add |
| // the same listener, for example, into the MyClickPad component you get fake |
| // Alt and Meta modifiers. I means that pressing of middle button causes |
| // Alt+Button2 event. |
| // See bug ID 4109826 on Sun's bug parade. |
| //cast is needed in order to compile with mustang |
| MouseShortcutDialog.this.addMouseListener((MouseListener)new MouseAdapter(){ |
| public void mouseReleased(MouseEvent e){ |
| Component component= SwingUtilities.getDeepestComponentAt(e.getComponent(),e.getX(),e.getY()); |
| if(component== MyClickPad.this){ |
| e.consume(); |
| myButton=e.getButton(); |
| myModifiers=e.getModifiersEx(); |
| updatePreviewAndConflicts(); |
| } |
| } |
| }); |
| } |
| } |
| } |