| /* |
| * 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.ui; |
| |
| import com.intellij.openapi.actionSystem.*; |
| import com.intellij.openapi.actionSystem.ex.ActionManagerEx; |
| import com.intellij.openapi.project.DumbAware; |
| import com.intellij.openapi.util.SystemInfo; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.ui.speedSearch.SpeedSearchSupply; |
| import com.intellij.util.IconUtil; |
| import com.intellij.util.containers.ContainerUtilRt; |
| import com.intellij.util.ui.MacUIUtil; |
| import com.intellij.util.ui.UIUtil; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import java.awt.*; |
| import java.awt.event.InputEvent; |
| import java.awt.event.KeyEvent; |
| import java.util.*; |
| |
| /** |
| * @author Konstantin Bulenkov |
| */ |
| public class CommonActionsPanel extends JPanel { |
| private final boolean myDecorateButtons; |
| |
| public enum Buttons { |
| ADD, REMOVE, EDIT, UP, DOWN; |
| |
| public static Buttons[] ALL = {ADD, REMOVE, EDIT, UP, DOWN}; |
| |
| public Icon getIcon() { |
| switch (this) { |
| case ADD: return IconUtil.getAddIcon(); |
| case EDIT: return IconUtil.getEditIcon(); |
| case REMOVE: return IconUtil.getRemoveIcon(); |
| case UP: return IconUtil.getMoveUpIcon(); |
| case DOWN: return IconUtil.getMoveDownIcon(); |
| } |
| return null; |
| } |
| |
| MyActionButton createButton(final Listener listener, String name, Icon icon) { |
| return new MyActionButton(this, listener, name == null ? StringUtil.capitalize(name().toLowerCase()) : name, icon); |
| } |
| |
| public String getText() { |
| return StringUtil.capitalize(name().toLowerCase()); |
| } |
| |
| public void performAction(Listener listener) { |
| switch (this) { |
| case ADD: listener.doAdd(); break; |
| case EDIT: listener.doEdit(); break; |
| case REMOVE: listener.doRemove(); break; |
| case UP: listener.doUp(); break; |
| case DOWN: listener.doDown(); break; |
| } |
| } |
| } |
| public interface Listener { |
| void doAdd(); |
| void doRemove(); |
| void doUp(); |
| void doDown(); |
| void doEdit(); |
| |
| class Adapter implements Listener { |
| @Override |
| public void doAdd() {} |
| @Override |
| public void doRemove() {} |
| @Override |
| public void doUp() {} |
| @Override |
| public void doDown() {} |
| @Override |
| public void doEdit() {} |
| } |
| } |
| |
| private Map<Buttons, MyActionButton> myButtons = new HashMap<Buttons, MyActionButton>(); |
| private final AnActionButton[] myActions; |
| |
| CommonActionsPanel(ListenerFactory factory, @Nullable JComponent contextComponent, ActionToolbarPosition position, |
| @Nullable AnActionButton[] additionalActions, @Nullable Comparator<AnActionButton> buttonComparator, |
| String addName, String removeName, String moveUpName, String moveDownName, String editName, |
| Icon addIcon, Buttons... buttons) { |
| super(new BorderLayout()); |
| final Listener listener = factory.createListener(this); |
| AnActionButton[] actions = new AnActionButton[buttons.length + (additionalActions == null ? 0 : additionalActions.length)]; |
| for (int i = 0; i < buttons.length; i++) { |
| Buttons button = buttons[i]; |
| String name = null; |
| switch (button) { |
| case ADD: name = addName; break; |
| case EDIT: name = editName; break; |
| case REMOVE: name = removeName; break; |
| case UP: name = moveUpName; break; |
| case DOWN: name = moveDownName; break; |
| } |
| final MyActionButton b = button.createButton(listener, name, button == Buttons.ADD && addIcon != null ? addIcon : button.getIcon()); |
| actions[i] = b; |
| myButtons.put(button, b); |
| } |
| if (additionalActions != null && additionalActions.length > 0) { |
| int i = buttons.length; |
| for (AnActionButton button : additionalActions) { |
| actions[i++] = button; |
| } |
| } |
| myActions = actions; |
| for (AnActionButton action : actions) { |
| action.setContextComponent(contextComponent); |
| } |
| if (buttonComparator != null) { |
| Arrays.sort(myActions, buttonComparator); |
| } |
| ArrayList<AnAction> toolbarActions = ContainerUtilRt.<AnAction>newArrayList(myActions); |
| for (int i = 0; i < toolbarActions.size(); i++) { |
| if (toolbarActions.get(i) instanceof AnActionButton.CheckedAnActionButton) { |
| toolbarActions.set(i, ((AnActionButton.CheckedAnActionButton)toolbarActions.get(i)).getDelegate()); |
| } |
| } |
| myDecorateButtons = UIUtil.isUnderAquaLookAndFeel() && position == ActionToolbarPosition.BOTTOM; |
| |
| final ActionManagerEx mgr = (ActionManagerEx)ActionManager.getInstance(); |
| final ActionToolbar toolbar = mgr.createActionToolbar(ActionPlaces.UNKNOWN, |
| new DefaultActionGroup(toolbarActions.toArray(new AnAction[toolbarActions.size()])), |
| position == ActionToolbarPosition.BOTTOM || position == ActionToolbarPosition.TOP, |
| myDecorateButtons); |
| toolbar.getComponent().setOpaque(false); |
| toolbar.getComponent().setBorder(null); |
| add(toolbar.getComponent(), BorderLayout.CENTER); |
| } |
| |
| @Override |
| protected void paintComponent(Graphics g2) { |
| final Graphics2D g = (Graphics2D)g2; |
| if (myDecorateButtons) { |
| MacUIUtil.drawToolbarDecoratorBackground(g, getWidth(), getHeight()); |
| } else { |
| super.paintComponent(g); |
| } |
| } |
| |
| public AnActionButton getAnActionButton(Buttons button) { |
| return myButtons.get(button); |
| } |
| |
| @Override |
| public void addNotify() { |
| if (getBackground() != null && !getBackground().equals(UIUtil.getPanelBackground())) { |
| SwingUtilities.updateComponentTreeUI(this.getParent()); |
| } |
| final JRootPane pane = getRootPane(); |
| for (AnActionButton button : myActions) { |
| final ShortcutSet shortcut = button.getShortcut(); |
| if (shortcut != null) { |
| if (button instanceof MyActionButton |
| && ((MyActionButton)button).isAddButton() |
| && UIUtil.isDialogRootPane(pane)) { |
| button.registerCustomShortcutSet(shortcut, pane); |
| } else { |
| button.registerCustomShortcutSet(shortcut, button.getContextComponent()); |
| } |
| if (button instanceof MyActionButton && ((MyActionButton)button).isRemoveButton()) { |
| registerDeleteHook((MyActionButton)button); |
| } |
| } |
| } |
| |
| super.addNotify(); // call after all to construct actions tooltips properly |
| } |
| |
| private static void registerDeleteHook(final MyActionButton removeButton) { |
| new AnAction("Delete Hook") { |
| @Override |
| public void actionPerformed(AnActionEvent e) { |
| removeButton.actionPerformed(e); |
| } |
| |
| @Override |
| public void update(AnActionEvent e) { |
| final JComponent contextComponent = removeButton.getContextComponent(); |
| if (contextComponent instanceof JTable && ((JTable)contextComponent).isEditing()) { |
| e.getPresentation().setEnabled(false); |
| return; |
| } |
| final SpeedSearchSupply supply = SpeedSearchSupply.getSupply(contextComponent); |
| if (supply != null && supply.isPopupActive()) { |
| e.getPresentation().setEnabled(false); |
| return; |
| } |
| removeButton.update(e); |
| } |
| }.registerCustomShortcutSet(CustomShortcutSet.fromString("DELETE", "BACK_SPACE"), removeButton.getContextComponent()); |
| } |
| |
| public void setEnabled(Buttons button, boolean enabled) { |
| final MyActionButton b = myButtons.get(button); |
| if (b != null) { |
| b.setEnabled(enabled); |
| } |
| } |
| |
| static class MyActionButton extends AnActionButton implements DumbAware { |
| private final Buttons myButton; |
| private final Listener myListener; |
| |
| MyActionButton(Buttons button, Listener listener, String name, Icon icon) { |
| super(name, name, icon); |
| myButton = button; |
| myListener = listener; |
| } |
| |
| @Override |
| public void actionPerformed(AnActionEvent e) { |
| myButton.performAction(myListener); |
| } |
| |
| @Override |
| public ShortcutSet getShortcut() { |
| return getCommonShortcut(myButton); |
| } |
| |
| @Override |
| public void updateButton(AnActionEvent e) { |
| super.updateButton(e); |
| if (!e.getPresentation().isEnabled()) return; |
| |
| final JComponent c = getContextComponent(); |
| if (c instanceof JTable || c instanceof JList) { |
| if (myButton == Buttons.EDIT) { |
| InputEvent inputEvent = e.getInputEvent(); |
| if (inputEvent instanceof KeyEvent && |
| c instanceof JTable && |
| ((JTable)c).isEditing() && |
| !(inputEvent.getComponent() instanceof ActionButtonComponent) // action button active in any case in the toolbar |
| ) { |
| e.getPresentation().setEnabled(false); |
| return; |
| } |
| } |
| |
| final ListSelectionModel model = c instanceof JTable ? ((JTable)c).getSelectionModel() |
| : ((JList)c).getSelectionModel(); |
| final int size = c instanceof JTable ? ((JTable)c).getRowCount() |
| : ((JList)c).getModel().getSize(); |
| final int min = model.getMinSelectionIndex(); |
| final int max = model.getMaxSelectionIndex(); |
| |
| if ((myButton == Buttons.UP && min < 1) |
| || (myButton == Buttons.DOWN && max == size - 1) |
| || (myButton != Buttons.ADD && size == 0) |
| || (myButton == Buttons.EDIT && (min != max || min == -1))) { |
| e.getPresentation().setEnabled(false); |
| } |
| else { |
| e.getPresentation().setEnabled(isEnabled()); |
| } |
| } |
| } |
| |
| //@Override |
| //public boolean isEnabled() { |
| // if (myButton == Buttons.REMOVE) { |
| // final JComponent c = getContextComponent(); |
| // if (c instanceof JTable && ((JTable)c).isEditing()) return false; |
| // } |
| // return super.isEnabled(); |
| //} |
| |
| boolean isAddButton() { |
| return myButton == Buttons.ADD; |
| } |
| |
| boolean isRemoveButton() { |
| return myButton == Buttons.REMOVE; |
| } |
| } |
| |
| public static ShortcutSet getCommonShortcut(Buttons button) { |
| switch (button) { |
| case ADD: return CommonShortcuts.getNewForDialogs(); |
| case EDIT: return CustomShortcutSet.fromString("ENTER"); |
| case REMOVE: return CustomShortcutSet.fromString(SystemInfo.isMac ? "meta BACK_SPACE" : "alt DELETE"); |
| case UP: return CommonShortcuts.MOVE_UP; |
| case DOWN: return CommonShortcuts.MOVE_DOWN; |
| } |
| return null; |
| } |
| |
| interface ListenerFactory { |
| Listener createListener(CommonActionsPanel panel); |
| } |
| } |