blob: ca0a51112f98b7a8039e98272ae3fd0f540a2211 [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.codeInsight.intention.impl.config;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.IntentionActionBean;
import com.intellij.codeInsight.intention.IntentionManager;
import com.intellij.codeInspection.GlobalInspectionTool;
import com.intellij.codeInspection.GlobalSimpleInspectionTool;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.actions.CleanupInspectionIntention;
import com.intellij.codeInspection.actions.RunInspectionIntention;
import com.intellij.codeInspection.ex.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.ExtensionPoint;
import com.intellij.openapi.extensions.ExtensionPointListener;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.extensions.PluginDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.Alarm;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* @author dsl
*/
public class IntentionManagerImpl extends IntentionManager {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.intention.impl.config.IntentionManagerImpl");
private final List<IntentionAction> myActions = ContainerUtil.createLockFreeCopyOnWriteList();
private final IntentionManagerSettings mySettings;
private final Alarm myInitActionsAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
public IntentionManagerImpl(IntentionManagerSettings intentionManagerSettings) {
mySettings = intentionManagerSettings;
addAction(new EditInspectionToolsSettingsInSuppressedPlaceIntention());
final ExtensionPoint<IntentionActionBean> point = Extensions.getArea(null).getExtensionPoint(EP_INTENTION_ACTIONS);
point.addExtensionPointListener(new ExtensionPointListener<IntentionActionBean>() {
@Override
public void extensionAdded(@NotNull final IntentionActionBean extension, @Nullable final PluginDescriptor pluginDescriptor) {
registerIntentionFromBean(extension);
}
@Override
public void extensionRemoved(@NotNull final IntentionActionBean extension, @Nullable final PluginDescriptor pluginDescriptor) {
}
});
}
private void registerIntentionFromBean(@NotNull final IntentionActionBean extension) {
final Runnable runnable = new Runnable() {
@Override
public void run() {
final String descriptionDirectoryName = extension.getDescriptionDirectoryName();
final String[] categories = extension.getCategories();
final IntentionAction instance = createIntentionActionWrapper(extension, categories);
if (categories == null) {
addAction(instance);
}
else {
if (descriptionDirectoryName != null) {
addAction(instance);
mySettings.registerIntentionMetaData(instance, categories, descriptionDirectoryName, extension.getMetadataClassLoader());
}
else {
registerIntentionAndMetaData(instance, categories);
}
}
}
};
//todo temporary hack, need smarter logic:
// * on the first request, wait until all the initialization is finished
// * ensure this request doesn't come on EDT
// * while waiting, check for ProcessCanceledException
if (ApplicationManager.getApplication().isUnitTestMode()) {
runnable.run();
}
else {
myInitActionsAlarm.addRequest(runnable, 300);
}
}
private static IntentionAction createIntentionActionWrapper(@NotNull IntentionActionBean intentionActionBean, String[] categories) {
return new IntentionActionWrapper(intentionActionBean, categories);
}
@Override
public void registerIntentionAndMetaData(@NotNull IntentionAction action, @NotNull String... category) {
registerIntentionAndMetaData(action, category, getDescriptionDirectoryName(action));
}
@NotNull
private static String getDescriptionDirectoryName(final IntentionAction action) {
if (action instanceof IntentionActionWrapper) {
final IntentionActionWrapper wrapper = (IntentionActionWrapper)action;
return getDescriptionDirectoryName(wrapper.getImplementationClassName());
}
else {
return getDescriptionDirectoryName(action.getClass().getName());
}
}
private static String getDescriptionDirectoryName(final String fqn) {
return fqn.substring(fqn.lastIndexOf('.') + 1).replaceAll("\\$", "");
}
@Override
public void registerIntentionAndMetaData(@NotNull IntentionAction action,
@NotNull String[] category,
@NotNull @NonNls String descriptionDirectoryName) {
addAction(action);
mySettings.registerIntentionMetaData(action, category, descriptionDirectoryName);
}
@Override
public void registerIntentionAndMetaData(@NotNull final IntentionAction action,
@NotNull final String[] category,
@NotNull final String description,
@NotNull final String exampleFileExtension,
@NotNull final String[] exampleTextBefore,
@NotNull final String[] exampleTextAfter) {
addAction(action);
IntentionActionMetaData metaData = new IntentionActionMetaData(action, category,
new PlainTextDescriptor(description, "description.html"),
mapToDescriptors(exampleTextBefore, "before." + exampleFileExtension),
mapToDescriptors(exampleTextAfter, "after." + exampleFileExtension));
mySettings.registerMetaData(metaData);
}
@Override
public void unregisterIntention(@NotNull IntentionAction intentionAction) {
myActions.remove(intentionAction);
mySettings.unregisterMetaData(intentionAction);
}
private static TextDescriptor[] mapToDescriptors(String[] texts, @NonNls String fileName) {
TextDescriptor[] result = new TextDescriptor[texts.length];
for (int i = 0; i < texts.length; i++) {
result[i] = new PlainTextDescriptor(texts[i], fileName);
}
return result;
}
@Override
@NotNull
public List<IntentionAction> getStandardIntentionOptions(@NotNull final HighlightDisplayKey displayKey,
@NotNull final PsiElement context) {
List<IntentionAction> options = new ArrayList<IntentionAction>(9);
options.add(new EditInspectionToolsSettingsAction(displayKey));
options.add(new RunInspectionIntention(displayKey));
options.add(new DisableInspectionToolAction(displayKey));
return options;
}
@Nullable
@Override
public IntentionAction createFixAllIntention(InspectionToolWrapper toolWrapper, IntentionAction action) {
if (toolWrapper instanceof LocalInspectionToolWrapper) {
Class aClass = action.getClass();
if (action instanceof QuickFixWrapper) {
aClass = ((QuickFixWrapper)action).getFix().getClass();
}
return new CleanupInspectionIntention(toolWrapper, aClass, action.getText());
}
else if (toolWrapper instanceof GlobalInspectionToolWrapper) {
GlobalInspectionTool wrappedTool = ((GlobalInspectionToolWrapper)toolWrapper).getTool();
if (wrappedTool instanceof GlobalSimpleInspectionTool && (action instanceof LocalQuickFix || action instanceof QuickFixWrapper)) {
Class aClass = action.getClass();
if (action instanceof QuickFixWrapper) {
aClass = ((QuickFixWrapper)action).getFix().getClass();
}
return new CleanupInspectionIntention(toolWrapper, aClass, action.getText());
}
}
else {
throw new AssertionError("unknown tool: " + toolWrapper);
}
return null;
}
@Override
@NotNull
public LocalQuickFix convertToFix(@NotNull final IntentionAction action) {
if (action instanceof LocalQuickFix) {
return (LocalQuickFix)action;
}
return new LocalQuickFix() {
@Override
@NotNull
public String getName() {
return action.getText();
}
@Override
@NotNull
public String getFamilyName() {
return action.getFamilyName();
}
@Override
public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) {
final PsiFile psiFile = descriptor.getPsiElement().getContainingFile();
try {
action.invoke(project, new LazyEditor(psiFile), psiFile);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
};
}
@Override
public void addAction(@NotNull IntentionAction action) {
myActions.add(action);
}
@Override
@NotNull
public IntentionAction[] getIntentionActions() {
return myActions.toArray(new IntentionAction[myActions.size()]);
}
@NotNull
@Override
public IntentionAction[] getAvailableIntentionActions() {
List<IntentionAction> list = new ArrayList<IntentionAction>(myActions.size());
for (IntentionAction action : myActions) {
if (mySettings.isEnabled(action)) {
list.add(action);
}
}
return list.toArray(new IntentionAction[list.size()]);
}
public boolean hasActiveRequests() {
return !myInitActionsAlarm.isEmpty();
}
}