blob: ed56542798593ba3777892bbb7a10a2cabe94888 [file] [log] [blame]
/*
* Copyright 2000-2009 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.ActionGroup;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.components.ExportableComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.keymap.impl.ui.ActionsTreeUtil;
import com.intellij.openapi.keymap.impl.ui.Group;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.openapi.wm.impl.IdeFrameImpl;
import com.intellij.util.ImageLoader;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;
/**
* User: anna
* Date: Jan 20, 2005
*/
public class CustomActionsSchema implements ExportableComponent, NamedJDOMExternalizable {
@NonNls private static final String ACTIONS_SCHEMA = "custom_actions_schema";
@NonNls private static final String ACTIVE = "active";
@NonNls private static final String ELEMENT_ACTION = "action";
@NonNls private static final String ATTRIBUTE_ID = "id";
@NonNls private static final String ATTRIBUTE_ICON = "icon";
private final Map<String, String> myIconCustomizations = new HashMap<String, String>();
private ArrayList<ActionUrl> myActions = new ArrayList<ActionUrl>();
private final HashMap<String , ActionGroup> myIdToActionGroup = new HashMap<String, ActionGroup>();
private final List<Pair> myIdToNameList = new ArrayList<Pair>();
@NonNls private static final String GROUP = "group";
private static final Logger LOG = Logger.getInstance("#" + CustomActionsSchema.class.getName());
public CustomActionsSchema() {
myIdToNameList.add(new Pair(IdeActions.GROUP_MAIN_MENU, ActionsTreeUtil.MAIN_MENU_TITLE));
myIdToNameList.add(new Pair(IdeActions.GROUP_MAIN_TOOLBAR, ActionsTreeUtil.MAIN_TOOLBAR));
myIdToNameList.add(new Pair(IdeActions.GROUP_EDITOR_POPUP, ActionsTreeUtil.EDITOR_POPUP));
myIdToNameList.add(new Pair(IdeActions.GROUP_EDITOR_GUTTER, "Editor Gutter Popup Menu"));
myIdToNameList.add(new Pair(IdeActions.GROUP_EDITOR_TAB_POPUP, ActionsTreeUtil.EDITOR_TAB_POPUP));
myIdToNameList.add(new Pair(IdeActions.GROUP_PROJECT_VIEW_POPUP, ActionsTreeUtil.PROJECT_VIEW_POPUP));
myIdToNameList.add(new Pair(IdeActions.GROUP_SCOPE_VIEW_POPUP, "Scope View Popup Menu"));
myIdToNameList.add(new Pair(IdeActions.GROUP_FAVORITES_VIEW_POPUP, ActionsTreeUtil.FAVORITES_POPUP));
myIdToNameList.add(new Pair(IdeActions.GROUP_COMMANDER_POPUP, ActionsTreeUtil.COMMANDER_POPUP));
myIdToNameList.add(new Pair(IdeActions.GROUP_J2EE_VIEW_POPUP, ActionsTreeUtil.J2EE_POPUP));
myIdToNameList.add(new Pair(IdeActions.GROUP_NAVBAR_POPUP, "Navigation Bar"));
myIdToNameList.add(new Pair("NavBarToolBar", "Navigation Bar Toolbar"));
CustomizableActionGroupProvider.CustomizableActionGroupRegistrar registrar =
new CustomizableActionGroupProvider.CustomizableActionGroupRegistrar() {
@Override
public void addCustomizableActionGroup(@NotNull String groupId, @NotNull String groupTitle) {
myIdToNameList.add(new Pair(groupId, groupTitle));
}
};
for (CustomizableActionGroupProvider provider : CustomizableActionGroupProvider.EP_NAME.getExtensions()) {
provider.registerGroups(registrar);
}
}
public static CustomActionsSchema getInstance() {
return ServiceManager.getService(CustomActionsSchema.class);
}
public void addAction(ActionUrl url) {
myActions.add(url);
resortActions();
}
public ArrayList<ActionUrl> getActions() {
return myActions;
}
public void setActions(final ArrayList<ActionUrl> actions) {
myActions = actions;
resortActions();
}
public void copyFrom(CustomActionsSchema result) {
myIdToActionGroup.clear();
myActions.clear();
myIconCustomizations.clear();
for (ActionUrl actionUrl : result.myActions) {
final ActionUrl url = new ActionUrl(new ArrayList<String>(actionUrl.getGroupPath()), actionUrl.getComponent(),
actionUrl.getActionType(), actionUrl.getAbsolutePosition());
url.setInitialPosition(actionUrl.getInitialPosition());
myActions.add(url);
}
resortActions();
myIconCustomizations.putAll(result.myIconCustomizations);
}
private void resortActions() {
Collections.sort(myActions, ActionUrlComparator.INSTANCE);
}
public boolean isModified(CustomActionsSchema schema) {
final ArrayList<ActionUrl> storedActions = schema.getActions();
if (ApplicationManager.getApplication().isUnitTestMode() && !storedActions.isEmpty()) {
System.err.println("stored: " + storedActions.toString());
System.err.println("actual: " + getActions().toString());
}
if (storedActions.size() != getActions().size()) {
return true;
}
for (int i = 0; i < getActions().size(); i++) {
if (!getActions().get(i).equals(storedActions.get(i))) {
return true;
}
}
if (schema.myIconCustomizations.size() != myIconCustomizations.size()) return true;
for (String actionId : myIconCustomizations.keySet()) {
if (!Comparing.strEqual(schema.getIconPath(actionId), getIconPath(actionId))) return true;
}
return false;
}
public void readExternal(Element element) throws InvalidDataException {
DefaultJDOMExternalizer.readExternal(this, element);
Element schElement = element;
final String activeName = element.getAttributeValue(ACTIVE);
if (activeName != null) {
for (Element toolbarElement : (Iterable<Element>)element.getChildren(ACTIONS_SCHEMA)) {
for (Object o : toolbarElement.getChildren("option")) {
if (Comparing.strEqual(((Element)o).getAttributeValue("name"), "myName") &&
Comparing.strEqual(((Element)o).getAttributeValue("value"), activeName)) {
schElement = toolbarElement;
break;
}
}
}
}
for (Object groupElement : schElement.getChildren(GROUP)) {
ActionUrl url = new ActionUrl();
url.readExternal((Element)groupElement);
myActions.add(url);
}
if (ApplicationManager.getApplication().isUnitTestMode()) {
System.err.println("read custom actions: " + myActions.toString());
}
readIcons(element);
}
public void writeExternal(Element element) throws WriteExternalException {
DefaultJDOMExternalizer.writeExternal(this, element);
writeActions(element);
writeIcons(element);
}
private void writeActions(Element element) throws WriteExternalException {
for (ActionUrl group : myActions) {
Element groupElement = new Element(GROUP);
group.writeExternal(groupElement);
element.addContent(groupElement);
}
}
public AnAction getCorrectedAction(String id) {
if (! myIdToNameList.contains(new Pair(id, ""))){
return ActionManager.getInstance().getAction(id);
}
if (myIdToActionGroup.get(id) == null) {
for (Pair pair : myIdToNameList) {
if (pair.first.equals(id)){
final ActionGroup actionGroup = (ActionGroup)ActionManager.getInstance().getAction(id);
if (actionGroup != null) { //J2EE/Commander plugin was disabled
myIdToActionGroup.put(id, CustomizationUtil.correctActionGroup(actionGroup, this, pair.second, pair.second));
}
}
}
}
return myIdToActionGroup.get(id);
}
public void resetMainActionGroups() {
for (Pair pair : myIdToNameList) {
final ActionGroup actionGroup = (ActionGroup)ActionManager.getInstance().getAction(pair.first);
if (actionGroup != null) { //J2EE/Commander plugin was disabled
myIdToActionGroup.put(pair.first, CustomizationUtil.correctActionGroup(actionGroup, this, pair.second, pair.second));
}
}
}
public void fillActionGroups(DefaultMutableTreeNode root){
final ActionManager actionManager = ActionManager.getInstance();
for (Pair pair : myIdToNameList) {
final ActionGroup actionGroup = (ActionGroup)actionManager.getAction(pair.first);
if (actionGroup != null) { //J2EE/Commander plugin was disabled
root.add(ActionsTreeUtil.createNode(ActionsTreeUtil.createGroup(actionGroup, pair.second, null, null, true, null, false)));
}
}
}
public boolean isCorrectActionGroup(ActionGroup group, String defaultGroupName) {
if (myActions.isEmpty()){
return false;
}
final String text = group.getTemplatePresentation().getText();
if (!StringUtil.isEmpty(text)) {
for (ActionUrl url : myActions) {
if (url.getGroupPath().contains(text) || url.getGroupPath().contains(defaultGroupName)) {
return true;
}
if (url.getComponent() instanceof Group) {
final Group urlGroup = (Group)url.getComponent();
String id = urlGroup.getName() != null ? urlGroup.getName() : urlGroup.getId();
if (id == null || id.equals(text) || id.equals(defaultGroupName)) {
return true;
}
}
}
return false;
}
return true;
}
public List<ActionUrl> getChildActions(final ActionUrl url) {
ArrayList<ActionUrl> result = new ArrayList<ActionUrl>();
final ArrayList<String> groupPath = url.getGroupPath();
for (ActionUrl actionUrl : myActions) {
int index = 0;
if (groupPath.size() <= actionUrl.getGroupPath().size()){
while (index < groupPath.size()){
if (!Comparing.equal(groupPath.get(index), actionUrl.getGroupPath().get(index))){
break;
}
index++;
}
if (index == groupPath.size()){
result.add(actionUrl);
}
}
}
return result;
}
public void removeIconCustomization(String actionId) {
myIconCustomizations.remove(actionId);
}
public void addIconCustomization(String actionId, String iconPath) {
myIconCustomizations.put(actionId, iconPath != null ? FileUtil.toSystemIndependentName(iconPath) : null);
}
public String getIconPath(String actionId) {
final String path = myIconCustomizations.get(actionId);
return path == null ? "" : path;
}
private void readIcons(Element parent) {
for (Object actionO : parent.getChildren(ELEMENT_ACTION)) {
Element action = (Element)actionO;
final String actionId = action.getAttributeValue(ATTRIBUTE_ID);
final String iconPath = action.getAttributeValue(ATTRIBUTE_ICON);
if (actionId != null){
myIconCustomizations.put(actionId, iconPath);
}
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
initActionIcons();
}
});
}
private void writeIcons(Element parent) {
for (String actionId : myIconCustomizations.keySet()) {
Element action = new Element(ELEMENT_ACTION);
action.setAttribute(ATTRIBUTE_ID, actionId);
String icon = myIconCustomizations.get(actionId);
if (icon != null) {
action.setAttribute(ATTRIBUTE_ICON, icon);
}
parent.addContent(action);
}
}
private void initActionIcons() {
ActionManager actionManager = ActionManager.getInstance();
for (String actionId : myIconCustomizations.keySet()) {
final AnAction anAction = actionManager.getAction(actionId);
if (anAction != null) {
Icon icon;
final String iconPath = myIconCustomizations.get(actionId);
if (iconPath != null && new File(FileUtil.toSystemDependentName(iconPath)).exists()) {
Image image = null;
try {
image = ImageLoader.loadFromStream(VfsUtil.convertToURL(VfsUtil.pathToUrl(iconPath)).openStream());
}
catch (IOException e) {
LOG.debug(e);
}
icon = image != null ? IconLoader.getIcon(image) : null;
}
else {
icon = AllIcons.Toolbar.Unknown;
}
if (anAction.getTemplatePresentation() != null) {
anAction.getTemplatePresentation().setIcon(icon);
anAction.getTemplatePresentation().setDisabledIcon(IconLoader.getDisabledIcon(icon));
anAction.setDefaultIcon(false);
}
}
}
final IdeFrameImpl frame = WindowManagerEx.getInstanceEx().getFrame(null);
if (frame != null) {
frame.updateView();
}
}
@NotNull
public File[] getExportFiles() {
return new File[]{PathManager.getOptionsFile(this)};
}
@NotNull
public String getPresentableName() {
return IdeBundle.message("title.custom.actions.schemas");
}
public String getExternalFileName() {
return "customization";
}
private static class Pair {
String first;
String second;
public Pair(final String first, final String second) {
this.first = first;
this.second = second;
}
public int hashCode() {
return first.hashCode();
}
public boolean equals(Object obj) {
return obj instanceof Pair && first.equals(((Pair)obj).first);
}
}
private static class ActionUrlComparator implements Comparator<ActionUrl> {
public static ActionUrlComparator INSTANCE = new ActionUrlComparator();
private static final int DELETED = 1;
private static final int ADDED = 2;
public int compare(ActionUrl u1, ActionUrl u2) {
final int w1 = getEquivalenceClass(u1);
final int w2 = getEquivalenceClass(u2);
if (w1 != w2) {
return w1 - w2; // deleted < added < others
}
if (w1 == DELETED) {
return u2.getAbsolutePosition() - u1.getAbsolutePosition(); // within DELETED equivalence class urls with greater position go first
}
return u1.getAbsolutePosition() - u2.getAbsolutePosition(); // within ADDED equivalence class: urls with lower position go first
}
private static int getEquivalenceClass(ActionUrl url) {
switch (url.getActionType()) {
case ActionUrl.DELETED: return 1;
case ActionUrl.ADDED: return 2;
default: return 3;
}
}
}
}