blob: feab7d7e544ebc9599929edbcaee27b1007faeb9 [file] [log] [blame]
/*
* Copyright 2000-2010 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.ui.switcher;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.KeyboardShortcut;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.SeparatorWithText;
import com.intellij.ui.components.panels.VerticalBox;
import com.intellij.util.ui.AwtVisitor;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.text.NumberFormat;
import java.util.*;
/**
* @author nik
*/
public class QuickAccessConfigurable extends JPanel implements SearchableConfigurable {
private Set<String> myModifiers = new HashSet<String>();
private boolean myQaEnabled;
private int myDelay;
private JCheckBox myEnabled;
private ModifierBox myCtrl;
private ModifierBox myAlt;
private ModifierBox myShift;
private ModifierBox myMeta;
private JPanel myConflicts;
private JFormattedTextField myHoldTime;
private QuickAccessSettings myQuickAccessSettings;
public QuickAccessConfigurable(QuickAccessSettings quickAccessSettings) {
myQuickAccessSettings = quickAccessSettings;
JPanel north = new JPanel(new BorderLayout());
VerticalBox box = new VerticalBox();
north.add(box, BorderLayout.NORTH);
setLayout(new BorderLayout());
add(north, BorderLayout.WEST);
myEnabled = new JCheckBox("Enable Quick Access");
myEnabled.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
myQaEnabled = myEnabled.isSelected();
processEnabled();
}
});
box.add(myEnabled);
VerticalBox kbConfig = new VerticalBox();
JPanel modifiers = new JPanel(new FlowLayout(FlowLayout.CENTER)) {
@Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
size.width *= 1.5;
return size;
}
};
myCtrl = new ModifierBox("control", KeyEvent.getKeyModifiersText(KeyEvent.CTRL_MASK));
myAlt = new ModifierBox("alt", KeyEvent.getKeyModifiersText(KeyEvent.ALT_MASK));
myShift = new ModifierBox("shift", KeyEvent.getKeyModifiersText(KeyEvent.SHIFT_MASK));
myMeta = new ModifierBox("meta", KeyEvent.getKeyModifiersText(KeyEvent.META_MASK));
modifiers.add(new JLabel("Modifiers:"));
modifiers.add(myCtrl);
modifiers.add(myAlt);
modifiers.add(myShift);
if (SystemInfo.isMac) {
modifiers.add(myMeta);
}
JPanel hold = new JPanel(new FlowLayout(FlowLayout.CENTER));
hold.add(new JLabel("Hold time:"));
myHoldTime = new JFormattedTextField(NumberFormat.getIntegerInstance());
myHoldTime.setColumns(5);
myHoldTime.setHorizontalAlignment(JTextField.RIGHT);
myHoldTime.getDocument().addDocumentListener(new DocumentAdapter() {
@Override
protected void textChanged(DocumentEvent e) {
String txt = myHoldTime.getText();
if (txt != null) {
try {
Integer value = Integer.valueOf(txt);
myDelay = value.intValue();
}
catch (NumberFormatException e1) {
}
}
}
});
hold.add(myHoldTime);
hold.add(new JLabel("ms"));
kbConfig.add(modifiers);
kbConfig.add(hold);
kbConfig.setBorder(IdeBorderFactory.createTitledBorder("Keyboard Configuration", true));
box.add(kbConfig);
myConflicts = new JPanel();
box.add(myConflicts);
updateConflicts();
}
private Set<String> getModifierTexts() {
HashSet<String> result = new HashSet<String>();
for (Integer each : myQuickAccessSettings.getModiferCodes()) {
if (each == KeyEvent.VK_SHIFT) {
result.add("shift");
}
else if (each == KeyEvent.VK_CONTROL) {
result.add("control");
}
else if (each == KeyEvent.VK_ALT) {
result.add("alt");
}
else if (each == KeyEvent.VK_META) {
result.add("meta");
}
}
return result;
}
private void updateConflicts() {
myConflicts.removeAll();
myConflicts.setBorder(null);
if (!myQaEnabled) {
return;
}
if (myModifiers.size() == 0) {
myConflicts.setLayout(new BorderLayout());
myConflicts.add(getSmallLabel("Without assigning modifier keys Quick Access will not function"), BorderLayout.NORTH);
return;
}
myConflicts.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(0, 4, 0, 4);
boolean hasConflicts = printConflict(c, KeyEvent.VK_UP, QuickAccessSettings.SWITCH_UP);
hasConflicts |= printConflict(c, KeyEvent.VK_DOWN, QuickAccessSettings.SWITCH_DOWN);
hasConflicts |= printConflict(c, KeyEvent.VK_LEFT, QuickAccessSettings.SWITCH_LEFT);
hasConflicts |= printConflict(c, KeyEvent.VK_RIGHT, QuickAccessSettings.SWITCH_RIGHT);
hasConflicts |= printConflict(c, KeyEvent.VK_ENTER, QuickAccessSettings.SWITCH_APPLY);
if (hasConflicts) {
myConflicts.setBorder(IdeBorderFactory.createTitledBorder("Conflicts", true));
c.gridx = 0;
c.gridy++;
c.gridwidth = 2;
myConflicts.add(new SeparatorWithText(), c);
c.gridx = 0;
c.gridy++;
myConflicts.add(getSmallLabel("These conflicting actions may be not what you use a lot"), c);
}
}
private static JLabel getSmallLabel(final String text) {
JLabel message = new JLabel(text, null, JLabel.CENTER);
message.setFont(message.getFont().deriveFont(message.getFont().getStyle(), message.getFont().getSize() - 2));
return message;
}
private boolean printConflict(GridBagConstraints c, int actionKey, String actionId) {
boolean hasConflicts = false;
int mask = myQuickAccessSettings.getModiferMask(myModifiers);
KeyboardShortcut sc = new KeyboardShortcut(KeyStroke.getKeyStroke(actionKey, mask), null);
Map<String,ArrayList<KeyboardShortcut>> conflictMap = myQuickAccessSettings.getKeymap().getConflicts(actionId, sc);
if (conflictMap.size() > 0) {
hasConflicts = true;
JLabel scText = new JLabel(sc.toString());
c.gridy++;
c.gridx = 0;
myConflicts.add(scText, c);
Iterator<String> actions = conflictMap.keySet().iterator();
while (actions.hasNext()) {
String each = actions.next();
AnAction eachAnAction = ActionManager.getInstance().getAction(each);
if (eachAnAction != null) {
String text = eachAnAction.getTemplatePresentation().getText();
JLabel eachAction = new JLabel(text != null && text.length() > 0 ? text : each);
c.gridx = 1;
myConflicts.add(eachAction, c);
c.gridy++;
}
}
}
c.gridx = 0;
c.gridwidth = 2;
c.gridy++;
myConflicts.add(new SeparatorWithText(), c);
c.gridwidth = 1;
return hasConflicts;
}
@Nls
public String getDisplayName() {
return "Quick Access";
}
public String getHelpTopic() {
return null;
}
public JComponent createComponent() {
return this;
}
@NotNull
public String getId() {
return "QuickAccess";
}
public Runnable enableSearch(String option) {
return null;
}
public boolean isModified() {
return !myModifiers.equals(getModifierTexts())
|| myQuickAccessSettings.isEnabled() != myEnabled.isSelected()
|| getHoldTime() != myDelay;
}
public void apply() throws ConfigurationException {
Registry.get("actionSystem.quickAccessEnabled").setValue(myEnabled.isSelected());
myQuickAccessSettings.saveModifiersToRegistry(myModifiers);
Registry.get("actionSystem.keyGestureHoldTime").setValue(myDelay);
}
public void reset() {
int delay = getHoldTime();
myQaEnabled = myQuickAccessSettings.isEnabled();
myModifiers.clear();
myModifiers.addAll(getModifierTexts());
myDelay = delay;
myEnabled.setSelected(myQaEnabled);
myCtrl.readMask();
myAlt.readMask();
myShift.readMask();
myMeta.readMask();
myHoldTime.setText(String.valueOf(delay));
processEnabled();
updateConflicts();
}
private static int getHoldTime() {
return Registry.intValue("actionSystem.keyGestureHoldTime");
}
public void disposeUIResources() {
}
private void processEnabled() {
new AwtVisitor(this) {
@Override
public boolean visit(Component component) {
if (component != myEnabled) {
component.setEnabled(myQaEnabled);
}
return false;
}
};
}
private class ModifierBox extends JCheckBox {
private String myModifierText;
private ModifierBox(String modifierText, String text) {
setText(text);
myModifierText = modifierText;
addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
applyMask();
updateConflicts();
}
});
}
private void applyMask() {
if (isSelected()) {
myModifiers.add(myModifierText);
}
else {
myModifiers.remove(myModifierText);
}
}
public boolean readMask() {
boolean selected = myModifiers.contains(myModifierText);
setSelected(selected);
return selected;
}
}
}