com.intellij.ide.ui.customization.CustomizableActionsPanel.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.ide.ui.customization.CustomizableActionsPanel.java

Source

/*
 * Copyright 2000-2013 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.ide.ui.customization;

import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeBundle;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnSeparator;
import com.intellij.openapi.actionSystem.ex.QuickList;
import com.intellij.openapi.actionSystem.ex.QuickListsManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.keymap.impl.ui.ActionsTree;
import com.intellij.openapi.keymap.impl.ui.ActionsTreeUtil;
import com.intellij.openapi.keymap.impl.ui.Group;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.openapi.wm.impl.IdeFrameImpl;
import com.intellij.packageDependencies.ui.TreeExpansionMonitor;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.InsertPathAction;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.ImageLoader;
import com.intellij.util.ObjectUtils;
import com.intellij.util.ui.EmptyIcon;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;

/**
 * User: anna
 * Date: Mar 17, 2005
 */
public class CustomizableActionsPanel {
    private static final Logger LOG = Logger
            .getInstance("#com.intellij.ide.ui.customization.CustomizableActionsPanel");

    private JButton myEditIconButton;
    private JButton myRemoveActionButton;
    private JButton myAddActionButton;
    private JButton myMoveActionDownButton;
    private JButton myMoveActionUpButton;
    private JPanel myPanel;
    private JTree myActionsTree;
    private JButton myAddSeparatorButton;

    private final TreeExpansionMonitor myTreeExpansionMonitor;

    private CustomActionsSchema mySelectedSchema;

    private JButton myRestoreAllDefaultButton;
    private JButton myRestoreDefaultButton;

    public CustomizableActionsPanel() {

        //noinspection HardCodedStringLiteral
        Group rootGroup = new Group("root", null, null);
        final DefaultMutableTreeNode root = new DefaultMutableTreeNode(rootGroup);
        DefaultTreeModel model = new DefaultTreeModel(root);
        myActionsTree.setModel(model);

        myActionsTree.setRootVisible(false);
        myActionsTree.setShowsRootHandles(true);
        UIUtil.setLineStyleAngled(myActionsTree);
        myActionsTree.setCellRenderer(new MyTreeCellRenderer());

        setButtonsDisabled();
        final ActionManager actionManager = ActionManager.getInstance();
        myActionsTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
            public void valueChanged(TreeSelectionEvent e) {
                final TreePath[] selectionPaths = myActionsTree.getSelectionPaths();
                final boolean isSingleSelection = selectionPaths != null && selectionPaths.length == 1;
                myAddActionButton.setEnabled(isSingleSelection);
                if (isSingleSelection) {
                    final DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectionPaths[0]
                            .getLastPathComponent();
                    String actionId = getActionId(node);
                    if (actionId != null) {
                        final AnAction action = actionManager.getAction(actionId);
                        myEditIconButton.setEnabled(action != null && action.getTemplatePresentation() != null);
                    } else {
                        myEditIconButton.setEnabled(false);
                    }
                } else {
                    myEditIconButton.setEnabled(false);
                }
                myAddSeparatorButton.setEnabled(isSingleSelection);
                myRemoveActionButton.setEnabled(selectionPaths != null);
                if (selectionPaths != null) {
                    for (TreePath selectionPath : selectionPaths) {
                        if (selectionPath.getPath() != null && selectionPath.getPath().length <= 2) {
                            setButtonsDisabled();
                            return;
                        }
                    }
                }
                myMoveActionUpButton.setEnabled(isMoveSupported(myActionsTree, -1));
                myMoveActionDownButton.setEnabled(isMoveSupported(myActionsTree, 1));
                myRestoreDefaultButton.setEnabled(!findActionsUnderSelection().isEmpty());
            }
        });

        myAddActionButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                final List<TreePath> expandedPaths = TreeUtil.collectExpandedPaths(myActionsTree);
                final TreePath selectionPath = myActionsTree.getLeadSelectionPath();
                if (selectionPath != null) {
                    DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectionPath.getLastPathComponent();
                    final FindAvailableActionsDialog dlg = new FindAvailableActionsDialog();
                    dlg.show();
                    if (dlg.isOK()) {
                        final Set<Object> toAdd = dlg.getTreeSelectedActionIds();
                        if (toAdd == null)
                            return;
                        for (final Object o : toAdd) {
                            final ActionUrl url = new ActionUrl(
                                    ActionUrl.getGroupPath(new TreePath(node.getPath())), o, ActionUrl.ADDED,
                                    node.getParent().getIndex(node) + 1);
                            addCustomizedAction(url);
                            ActionUrl.changePathInActionsTree(myActionsTree, url);
                            if (o instanceof String) {
                                DefaultMutableTreeNode current = new DefaultMutableTreeNode(url.getComponent());
                                current.setParent((DefaultMutableTreeNode) node.getParent());
                                editToolbarIcon((String) o, current);
                            }
                        }
                        ((DefaultTreeModel) myActionsTree.getModel()).reload();
                    }
                }
                TreeUtil.restoreExpandedPaths(myActionsTree, expandedPaths);
            }
        });

        myEditIconButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                myRestoreAllDefaultButton.setEnabled(true);
                final List<TreePath> expandedPaths = TreeUtil.collectExpandedPaths(myActionsTree);
                final TreePath selectionPath = myActionsTree.getLeadSelectionPath();
                if (selectionPath != null) {
                    EditIconDialog dlg = new EditIconDialog(
                            (DefaultMutableTreeNode) selectionPath.getLastPathComponent());
                    dlg.show();
                    if (dlg.isOK()) {
                        myActionsTree.repaint();
                    }
                }
                TreeUtil.restoreExpandedPaths(myActionsTree, expandedPaths);
            }
        });

        myAddSeparatorButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                final List<TreePath> expandedPaths = TreeUtil.collectExpandedPaths(myActionsTree);
                final TreePath selectionPath = myActionsTree.getLeadSelectionPath();
                if (selectionPath != null) {
                    DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectionPath.getLastPathComponent();
                    final ActionUrl url = new ActionUrl(ActionUrl.getGroupPath(selectionPath),
                            AnSeparator.getInstance(), ActionUrl.ADDED, node.getParent().getIndex(node) + 1);
                    ActionUrl.changePathInActionsTree(myActionsTree, url);
                    addCustomizedAction(url);
                    ((DefaultTreeModel) myActionsTree.getModel()).reload();
                }
                TreeUtil.restoreExpandedPaths(myActionsTree, expandedPaths);
            }
        });

        myRemoveActionButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                final List<TreePath> expandedPaths = TreeUtil.collectExpandedPaths(myActionsTree);
                final TreePath[] selectionPath = myActionsTree.getSelectionPaths();
                if (selectionPath != null) {
                    for (TreePath treePath : selectionPath) {
                        final ActionUrl url = CustomizationUtil.getActionUrl(treePath, ActionUrl.DELETED);
                        ActionUrl.changePathInActionsTree(myActionsTree, url);
                        addCustomizedAction(url);
                    }
                    ((DefaultTreeModel) myActionsTree.getModel()).reload();
                }
                TreeUtil.restoreExpandedPaths(myActionsTree, expandedPaths);
            }
        });

        myMoveActionUpButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                final List<TreePath> expandedPaths = TreeUtil.collectExpandedPaths(myActionsTree);
                final TreePath[] selectionPath = myActionsTree.getSelectionPaths();
                if (selectionPath != null) {
                    for (TreePath treePath : selectionPath) {
                        final ActionUrl url = CustomizationUtil.getActionUrl(treePath, ActionUrl.MOVE);
                        final int absolutePosition = url.getAbsolutePosition();
                        url.setInitialPosition(absolutePosition);
                        url.setAbsolutePosition(absolutePosition - 1);
                        ActionUrl.changePathInActionsTree(myActionsTree, url);
                        addCustomizedAction(url);
                    }
                    ((DefaultTreeModel) myActionsTree.getModel()).reload();
                    TreeUtil.restoreExpandedPaths(myActionsTree, expandedPaths);
                    for (TreePath path : selectionPath) {
                        myActionsTree.addSelectionPath(path);
                    }
                }
            }
        });

        myMoveActionDownButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                final List<TreePath> expandedPaths = TreeUtil.collectExpandedPaths(myActionsTree);
                final TreePath[] selectionPath = myActionsTree.getSelectionPaths();
                if (selectionPath != null) {
                    for (int i = selectionPath.length - 1; i >= 0; i--) {
                        TreePath treePath = selectionPath[i];
                        final ActionUrl url = CustomizationUtil.getActionUrl(treePath, ActionUrl.MOVE);
                        final int absolutePosition = url.getAbsolutePosition();
                        url.setInitialPosition(absolutePosition);
                        url.setAbsolutePosition(absolutePosition + 1);
                        ActionUrl.changePathInActionsTree(myActionsTree, url);
                        addCustomizedAction(url);
                    }
                    ((DefaultTreeModel) myActionsTree.getModel()).reload();
                    TreeUtil.restoreExpandedPaths(myActionsTree, expandedPaths);
                    for (TreePath path : selectionPath) {
                        myActionsTree.addSelectionPath(path);
                    }
                }
            }
        });

        myRestoreAllDefaultButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                mySelectedSchema.copyFrom(new CustomActionsSchema());
                patchActionsTreeCorrespondingToSchema(root);
                myRestoreAllDefaultButton.setEnabled(false);
            }
        });

        myRestoreDefaultButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                final List<ActionUrl> otherActions = new ArrayList<ActionUrl>(mySelectedSchema.getActions());
                otherActions.removeAll(findActionsUnderSelection());
                mySelectedSchema.copyFrom(new CustomActionsSchema());
                for (ActionUrl otherAction : otherActions) {
                    mySelectedSchema.addAction(otherAction);
                }
                final List<TreePath> treePaths = TreeUtil.collectExpandedPaths(myActionsTree);
                patchActionsTreeCorrespondingToSchema(root);
                restorePathsAfterTreeOptimization(treePaths);
                myRestoreDefaultButton.setEnabled(false);
            }
        });

        patchActionsTreeCorrespondingToSchema(root);

        myTreeExpansionMonitor = TreeExpansionMonitor.install(myActionsTree);
    }

    private List<ActionUrl> findActionsUnderSelection() {
        final ArrayList<ActionUrl> actions = new ArrayList<ActionUrl>();
        final TreePath[] selectionPaths = myActionsTree.getSelectionPaths();
        if (selectionPaths != null) {
            for (TreePath path : selectionPaths) {
                final ActionUrl selectedUrl = CustomizationUtil.getActionUrl(path, ActionUrl.MOVE);
                final ArrayList<String> selectedGroupPath = new ArrayList<String>(selectedUrl.getGroupPath());
                final Object component = selectedUrl.getComponent();
                if (component instanceof Group) {
                    selectedGroupPath.add(((Group) component).getName());
                    for (ActionUrl action : mySelectedSchema.getActions()) {
                        final ArrayList<String> groupPath = action.getGroupPath();
                        final int idx = Collections.indexOfSubList(groupPath, selectedGroupPath);
                        if (idx > -1) {
                            actions.add(action);
                        }
                    }
                }
            }
        }
        return actions;
    }

    private void addCustomizedAction(ActionUrl url) {
        mySelectedSchema.addAction(url);
        myRestoreAllDefaultButton.setEnabled(true);
    }

    private void editToolbarIcon(String actionId, DefaultMutableTreeNode node) {
        final AnAction anAction = ActionManager.getInstance().getAction(actionId);
        if (isToolbarAction(node) && anAction.getTemplatePresentation() != null
                && anAction.getTemplatePresentation().getIcon() == null) {
            final int exitCode = Messages.showOkCancelDialog(
                    IdeBundle.message("error.adding.action.without.icon.to.toolbar"),
                    IdeBundle.message("title.unable.to.add.action.without.icon.to.toolbar"),
                    Messages.getInformationIcon());
            if (exitCode == Messages.OK) {
                mySelectedSchema.addIconCustomization(actionId, null);
                anAction.getTemplatePresentation().setIcon(AllIcons.Toolbar.Unknown);
                anAction.setDefaultIcon(false);
                node.setUserObject(Pair.create(actionId, AllIcons.Toolbar.Unknown));
                myActionsTree.repaint();
                setCustomizationSchemaForCurrentProjects();
            }
        }
    }

    private void setButtonsDisabled() {
        myRemoveActionButton.setEnabled(false);
        myAddActionButton.setEnabled(false);
        myEditIconButton.setEnabled(false);
        myAddSeparatorButton.setEnabled(false);
        myMoveActionDownButton.setEnabled(false);
        myMoveActionUpButton.setEnabled(false);
    }

    private static boolean isMoveSupported(JTree tree, int dir) {
        final TreePath[] selectionPaths = tree.getSelectionPaths();
        if (selectionPaths != null) {
            DefaultMutableTreeNode parent = null;
            for (TreePath treePath : selectionPaths)
                if (treePath.getLastPathComponent() != null) {
                    final DefaultMutableTreeNode node = (DefaultMutableTreeNode) treePath.getLastPathComponent();
                    if (parent == null) {
                        parent = (DefaultMutableTreeNode) node.getParent();
                    }
                    if (parent != node.getParent()) {
                        return false;
                    }
                    if (dir > 0) {
                        if (parent.getIndex(node) == parent.getChildCount() - 1) {
                            return false;
                        }
                    } else {
                        if (parent.getIndex(node) == 0) {
                            return false;
                        }
                    }
                }
            return true;
        }
        return false;
    }

    public JPanel getPanel() {
        return myPanel;
    }

    private static void setCustomizationSchemaForCurrentProjects() {
        final Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
        for (Project project : openProjects) {
            final IdeFrameImpl frame = WindowManagerEx.getInstanceEx().getFrame(project);
            if (frame != null) {
                frame.updateView();
            }

            //final FavoritesManager favoritesView = FavoritesManager.getInstance(project);
            //final String[] availableFavoritesLists = favoritesView.getAvailableFavoritesLists();
            //for (String favoritesList : availableFavoritesLists) {
            //  favoritesView.getFavoritesTreeViewPanel(favoritesList).updateTreePopupHandler();
            //}
        }
        final IdeFrameImpl frame = WindowManagerEx.getInstanceEx().getFrame(null);
        if (frame != null) {
            frame.updateView();
        }
    }

    public void apply() throws ConfigurationException {
        final List<TreePath> treePaths = TreeUtil.collectExpandedPaths(myActionsTree);
        if (mySelectedSchema != null) {
            CustomizationUtil.optimizeSchema(myActionsTree, mySelectedSchema);
        }
        restorePathsAfterTreeOptimization(treePaths);
        CustomActionsSchema.getInstance().copyFrom(mySelectedSchema);
        setCustomizationSchemaForCurrentProjects();
    }

    private void restorePathsAfterTreeOptimization(final List<TreePath> treePaths) {
        for (final TreePath treePath : treePaths) {
            myActionsTree.expandPath(CustomizationUtil.getPathByUserObjects(myActionsTree, treePath));
        }
    }

    public void reset() {
        mySelectedSchema = new CustomActionsSchema();
        mySelectedSchema.copyFrom(CustomActionsSchema.getInstance());
        patchActionsTreeCorrespondingToSchema((DefaultMutableTreeNode) myActionsTree.getModel().getRoot());
        myRestoreAllDefaultButton.setEnabled(mySelectedSchema.isModified(new CustomActionsSchema()));
    }

    public boolean isModified() {
        CustomizationUtil.optimizeSchema(myActionsTree, mySelectedSchema);
        return CustomActionsSchema.getInstance().isModified(mySelectedSchema);
    }

    private void patchActionsTreeCorrespondingToSchema(DefaultMutableTreeNode root) {
        root.removeAllChildren();
        if (mySelectedSchema != null) {
            mySelectedSchema.fillActionGroups(root);
            for (final ActionUrl actionUrl : mySelectedSchema.getActions()) {
                ActionUrl.changePathInActionsTree(myActionsTree, actionUrl);
            }
        }
        ((DefaultTreeModel) myActionsTree.getModel()).reload();
    }

    private static class MyTreeCellRenderer extends DefaultTreeCellRenderer {
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded,
                boolean leaf, int row, boolean hasFocus) {
            super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
            if (value instanceof DefaultMutableTreeNode) {
                Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
                Icon icon = null;
                if (userObject instanceof Group) {
                    Group group = (Group) userObject;
                    String name = group.getName();
                    setText(name != null ? name : group.getId());
                    icon = ObjectUtils.notNull(group.getIcon(), AllIcons.Nodes.Folder);
                } else if (userObject instanceof String) {
                    String actionId = (String) userObject;
                    AnAction action = ActionManager.getInstance().getAction(actionId);
                    String name = action != null ? action.getTemplatePresentation().getText() : null;
                    setText(!StringUtil.isEmptyOrSpaces(name) ? name : actionId);
                    if (action != null) {
                        Icon actionIcon = action.getTemplatePresentation().getIcon();
                        if (actionIcon != null) {
                            icon = actionIcon;
                        }
                    }
                } else if (userObject instanceof Pair) {
                    String actionId = (String) ((Pair) userObject).first;
                    AnAction action = ActionManager.getInstance().getAction(actionId);
                    setText(action != null ? action.getTemplatePresentation().getText() : actionId);
                    icon = (Icon) ((Pair) userObject).second;
                } else if (userObject instanceof AnSeparator) {
                    setText("-------------");
                } else if (userObject instanceof QuickList) {
                    setText(((QuickList) userObject).getDisplayName());
                    icon = AllIcons.Actions.QuickList;
                } else {
                    throw new IllegalArgumentException("unknown userObject: " + userObject);
                }

                setIcon(ActionsTree.getEvenIcon(icon));

                if (sel) {
                    setForeground(UIUtil.getTreeSelectionForeground());
                } else {
                    setForeground(UIUtil.getTreeForeground());
                }
            }
            return this;
        }
    }

    private static boolean isToolbarAction(DefaultMutableTreeNode node) {
        return node.getParent() != null
                && ((DefaultMutableTreeNode) node.getParent()).getUserObject() instanceof Group
                && ((Group) ((DefaultMutableTreeNode) node.getParent()).getUserObject()).getName()
                        .equals(ActionsTreeUtil.MAIN_TOOLBAR);
    }

    @Nullable
    private static String getActionId(DefaultMutableTreeNode node) {
        return (String) (node.getUserObject() instanceof String ? node.getUserObject()
                : node.getUserObject() instanceof Pair ? ((Pair) node.getUserObject()).first : null);
    }

    protected boolean doSetIcon(DefaultMutableTreeNode node, @Nullable String path, Component component) {
        if (StringUtil.isNotEmpty(path) && !new File(path).isFile()) {
            Messages.showErrorDialog(component, IdeBundle.message("error.file.not.found.message", path),
                    IdeBundle.message("title.choose.action.icon"));
            return false;
        }

        String actionId = getActionId(node);
        if (actionId == null)
            return false;

        final AnAction action = ActionManager.getInstance().getAction(actionId);
        if (action != null && action.getTemplatePresentation() != null) {
            if (StringUtil.isNotEmpty(path)) {
                Image image = null;
                try {
                    image = ImageLoader.loadFromStream(VfsUtil
                            .convertToURL(VfsUtil.pathToUrl(path.replace(File.separatorChar, '/'))).openStream());
                } catch (IOException e) {
                    LOG.debug(e);
                }
                Icon icon = new File(path).exists() ? IconLoader.getIcon(image) : null;
                if (icon != null) {
                    if (icon.getIconWidth() > EmptyIcon.ICON_18.getIconWidth()
                            || icon.getIconHeight() > EmptyIcon.ICON_18.getIconHeight()) {
                        Messages.showErrorDialog(component, IdeBundle.message("custom.icon.validation.message"),
                                IdeBundle.message("title.choose.action.icon"));
                        return false;
                    }
                    node.setUserObject(Pair.create(actionId, icon));
                    mySelectedSchema.addIconCustomization(actionId, path);
                }
            } else {
                node.setUserObject(Pair.create(actionId, null));
                mySelectedSchema.removeIconCustomization(actionId);
                final DefaultMutableTreeNode nodeOnToolbar = findNodeOnToolbar(actionId);
                if (nodeOnToolbar != null) {
                    editToolbarIcon(actionId, nodeOnToolbar);
                    node.setUserObject(nodeOnToolbar.getUserObject());
                }
            }
            return true;
        }
        return false;
    }

    private static TextFieldWithBrowseButton createBrowseField() {
        TextFieldWithBrowseButton textField = new TextFieldWithBrowseButton();
        textField.setPreferredSize(new Dimension(200, textField.getPreferredSize().height));
        textField.setMinimumSize(new Dimension(200, textField.getPreferredSize().height));
        final FileChooserDescriptor fileChooserDescriptor = new FileChooserDescriptor(true, false, false, false,
                false, false) {
            public boolean isFileSelectable(VirtualFile file) {
                //noinspection HardCodedStringLiteral
                return file.getName().endsWith(".png");
            }
        };
        textField.addBrowseFolderListener(IdeBundle.message("title.browse.icon"),
                IdeBundle.message("prompt.browse.icon.for.selected.action"), null, fileChooserDescriptor);
        InsertPathAction.addTo(textField.getTextField(), fileChooserDescriptor);
        return textField;
    }

    private class EditIconDialog extends DialogWrapper {
        private final DefaultMutableTreeNode myNode;
        protected TextFieldWithBrowseButton myTextField;

        protected EditIconDialog(DefaultMutableTreeNode node) {
            super(false);
            setTitle(IdeBundle.message("title.choose.action.icon"));
            init();
            myNode = node;
            final String actionId = getActionId(node);
            if (actionId != null) {
                final String iconPath = mySelectedSchema.getIconPath(actionId);
                myTextField.setText(FileUtil.toSystemDependentName(iconPath));
            }
        }

        @Override
        public JComponent getPreferredFocusedComponent() {
            return myTextField.getChildComponent();
        }

        protected String getDimensionServiceKey() {
            return getClass().getName();
        }

        protected JComponent createCenterPanel() {
            myTextField = createBrowseField();
            JPanel northPanel = new JPanel(new BorderLayout());
            northPanel.add(myTextField, BorderLayout.NORTH);
            return northPanel;
        }

        protected void doOKAction() {
            if (myNode != null) {
                if (!doSetIcon(myNode, myTextField.getText(), getContentPane())) {
                    return;
                }
                final Object userObject = myNode.getUserObject();
                if (userObject instanceof Pair) {
                    String actionId = (String) ((Pair) userObject).first;
                    final AnAction action = ActionManager.getInstance().getAction(actionId);
                    final Icon icon = (Icon) ((Pair) userObject).second;
                    action.getTemplatePresentation().setIcon(icon);
                    action.setDefaultIcon(icon == null);
                    editToolbarIcon(actionId, myNode);
                }
                myActionsTree.repaint();
            }
            setCustomizationSchemaForCurrentProjects();
            super.doOKAction();
        }
    }

    @Nullable
    private DefaultMutableTreeNode findNodeOnToolbar(String actionId) {
        final TreeNode toolbar = ((DefaultMutableTreeNode) myActionsTree.getModel().getRoot()).getChildAt(1);
        for (int i = 0; i < toolbar.getChildCount(); i++) {
            final DefaultMutableTreeNode child = (DefaultMutableTreeNode) toolbar.getChildAt(i);
            final String childId = getActionId(child);
            if (childId != null && childId.equals(actionId)) {
                return child;
            }
        }
        return null;
    }

    private class FindAvailableActionsDialog extends DialogWrapper {
        private JTree myTree;
        private JButton mySetIconButton;
        private TextFieldWithBrowseButton myTextField;

        FindAvailableActionsDialog() {
            super(false);
            setTitle(IdeBundle.message("action.choose.actions.to.add"));
            init();
        }

        protected JComponent createCenterPanel() {
            Group rootGroup = ActionsTreeUtil.createMainGroup(null, null,
                    QuickListsManager.getInstance().getAllQuickLists());
            DefaultMutableTreeNode root = ActionsTreeUtil.createNode(rootGroup);
            DefaultTreeModel model = new DefaultTreeModel(root);
            myTree = new Tree();
            myTree.setModel(model);
            myTree.setCellRenderer(new MyTreeCellRenderer());
            final ActionManager actionManager = ActionManager.getInstance();

            mySetIconButton = new JButton(IdeBundle.message("button.set.icon"));
            mySetIconButton.setEnabled(false);
            mySetIconButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    final TreePath selectionPath = myTree.getSelectionPath();
                    if (selectionPath != null) {
                        doSetIcon((DefaultMutableTreeNode) selectionPath.getLastPathComponent(),
                                myTextField.getText(), getContentPane());
                        myTree.repaint();
                    }
                }
            });
            myTextField = createBrowseField();
            myTextField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() {
                protected void textChanged(DocumentEvent e) {
                    enableSetIconButton(actionManager);
                }
            });
            JPanel northPanel = new JPanel(new BorderLayout());
            northPanel.add(myTextField, BorderLayout.CENTER);
            final JLabel label = new JLabel(IdeBundle.message("label.icon.path"));
            label.setLabelFor(myTextField.getChildComponent());
            northPanel.add(label, BorderLayout.WEST);
            northPanel.add(mySetIconButton, BorderLayout.EAST);
            northPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
            JPanel panel = new JPanel(new BorderLayout());
            panel.add(northPanel, BorderLayout.NORTH);

            panel.add(ScrollPaneFactory.createScrollPane(myTree), BorderLayout.CENTER);
            myTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
                public void valueChanged(TreeSelectionEvent e) {
                    enableSetIconButton(actionManager);
                    final TreePath selectionPath = myTree.getSelectionPath();
                    if (selectionPath != null) {
                        final DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectionPath
                                .getLastPathComponent();
                        final String actionId = getActionId(node);
                        if (actionId != null) {
                            final String iconPath = mySelectedSchema.getIconPath(actionId);
                            myTextField.setText(FileUtil.toSystemDependentName(iconPath));
                        }
                    }
                }
            });
            return panel;
        }

        protected void doOKAction() {
            final ActionManager actionManager = ActionManager.getInstance();
            TreeUtil.traverseDepth((TreeNode) myTree.getModel().getRoot(), new TreeUtil.Traverse() {
                public boolean accept(Object node) {
                    if (node instanceof DefaultMutableTreeNode) {
                        final DefaultMutableTreeNode mutableNode = (DefaultMutableTreeNode) node;
                        final Object userObject = mutableNode.getUserObject();
                        if (userObject instanceof Pair) {
                            String actionId = (String) ((Pair) userObject).first;
                            final AnAction action = actionManager.getAction(actionId);
                            Icon icon = (Icon) ((Pair) userObject).second;
                            action.getTemplatePresentation().setIcon(icon);
                            action.setDefaultIcon(icon == null);
                            editToolbarIcon(actionId, mutableNode);
                        }
                    }
                    return true;
                }
            });
            super.doOKAction();
            setCustomizationSchemaForCurrentProjects();
        }

        protected void enableSetIconButton(ActionManager actionManager) {
            final TreePath selectionPath = myTree.getSelectionPath();
            Object userObject = null;
            if (selectionPath != null) {
                userObject = ((DefaultMutableTreeNode) selectionPath.getLastPathComponent()).getUserObject();
                if (userObject instanceof String) {
                    final AnAction action = actionManager.getAction((String) userObject);
                    if (action != null && action.getTemplatePresentation() != null
                            && action.getTemplatePresentation().getIcon() != null) {
                        mySetIconButton.setEnabled(true);
                        return;
                    }
                }
            }
            mySetIconButton.setEnabled(myTextField.getText().length() != 0 && selectionPath != null
                    && new DefaultMutableTreeNode(selectionPath).isLeaf() && !(userObject instanceof AnSeparator));
        }

        @Nullable
        public Set<Object> getTreeSelectedActionIds() {
            TreePath[] paths = myTree.getSelectionPaths();
            if (paths == null)
                return null;

            Set<Object> actions = new HashSet<Object>();
            for (TreePath path : paths) {
                Object node = path.getLastPathComponent();
                if (node instanceof DefaultMutableTreeNode) {
                    DefaultMutableTreeNode defNode = (DefaultMutableTreeNode) node;
                    Object userObject = defNode.getUserObject();
                    actions.add(userObject);
                }
            }
            return actions;
        }

        protected String getDimensionServiceKey() {
            return "#com.intellij.ide.ui.customization.CustomizableActionsPanel.FindAvailableActionsDialog";
        }
    }
}