/*
* Copyright 2000-2015 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;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.impl.ShowIntentionsPass;
import com.intellij.codeInsight.hint.*;
import com.intellij.codeInsight.intention.HighPriorityAction;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.impl.config.IntentionActionWrapper;
import com.intellij.codeInsight.intention.impl.config.IntentionManagerSettings;
import com.intellij.codeInsight.intention.impl.config.IntentionSettingsConfigurable;
import com.intellij.codeInsight.unwrap.ScopeHighlighter;
import com.intellij.codeInspection.SuppressIntentionActionFromFix;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.VisualPosition;
import com.intellij.openapi.editor.actions.EditorActionUtil;
import com.intellij.openapi.editor.colors.EditorColors;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.event.EditorFactoryAdapter;
import com.intellij.openapi.editor.event.EditorFactoryEvent;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.*;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.refactoring.BaseRefactoringIntentionAction;
import com.intellij.ui.HintHint;
import com.intellij.ui.LightweightHint;
import com.intellij.ui.PopupMenuListenerAdapter;
import com.intellij.ui.RowIcon;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.popup.WizardPopup;
import com.intellij.util.Alarm;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ThreeState;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.EmptyIcon;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collections;
import java.util.List;
/**
* @author max
* @author Mike
* @author Valentin
* @author Eugene Belyaev
* @author Konstantin Bulenkov
* @author and me too (Chinee?)
*/
public class IntentionHintComponent implements Disposable, ScrollAwareHint {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.intention.impl.IntentionHintComponent.ListPopupRunnable");
private static final Icon ourInactiveArrowIcon = new EmptyIcon(AllIcons.General.ArrowDown.getIconWidth(), AllIcons.General.ArrowDown.getIconHeight());
private static final int NORMAL_BORDER_SIZE = 6;
private static final int SMALL_BORDER_SIZE = 4;
private static final Border INACTIVE_BORDER = BorderFactory.createEmptyBorder(NORMAL_BORDER_SIZE, NORMAL_BORDER_SIZE, NORMAL_BORDER_SIZE, NORMAL_BORDER_SIZE);
private static final Border INACTIVE_BORDER_SMALL = BorderFactory.createEmptyBorder(SMALL_BORDER_SIZE, SMALL_BORDER_SIZE, SMALL_BORDER_SIZE, SMALL_BORDER_SIZE);
private static Border createActiveBorder() {
return BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(getBorderColor(), 1), BorderFactory.createEmptyBorder(NORMAL_BORDER_SIZE - 1, NORMAL_BORDER_SIZE-1, NORMAL_BORDER_SIZE-1, NORMAL_BORDER_SIZE-1));
}
private static Border createActiveBorderSmall() {
return BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(getBorderColor(), 1), BorderFactory.createEmptyBorder(SMALL_BORDER_SIZE-1, SMALL_BORDER_SIZE-1, SMALL_BORDER_SIZE-1, SMALL_BORDER_SIZE-1));
}
private static Color getBorderColor() {
return EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.SELECTED_TEARLINE_COLOR);
}
public boolean isVisible() {
return myPanel.isVisible();
}
private final Editor myEditor;
private static final Alarm myAlarm = new Alarm();
private final RowIcon myHighlightedIcon;
private final JLabel myIconLabel;
private final RowIcon myInactiveIcon;
private static final int DELAY = 500;
private final MyComponentHint myComponentHint;
private volatile boolean myPopupShown;
private boolean myDisposed;
private volatile ListPopup myPopup;
private final PsiFile myFile;
private final JPanel myPanel = new JPanel();
private PopupMenuListener myOuterComboboxPopupListener;
@NotNull
public static IntentionHintComponent showIntentionHint(@NotNull Project project,
@NotNull PsiFile file,
@NotNull Editor editor,
@NotNull ShowIntentionsPass.IntentionsInfo intentions,
boolean showExpanded) {
ApplicationManager.getApplication().assertIsDispatchThread();
final Point position = getHintPosition(editor);
return showIntentionHint(project, file, editor, intentions, showExpanded, position);
}
@NotNull
public static IntentionHintComponent showIntentionHint(@NotNull final Project project,
@NotNull PsiFile file,
@NotNull final Editor editor,
@NotNull ShowIntentionsPass.IntentionsInfo intentions,
boolean showExpanded,
@NotNull Point position) {
ApplicationManager.getApplication().assertIsDispatchThread();
final IntentionHintComponent component = new IntentionHintComponent(project, file, editor, intentions);
component.showIntentionHintImpl(!showExpanded, position);
Disposer.register(project, component);
if (showExpanded) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
if (!editor.isDisposed() && editor.getComponent().isShowing()) {
component.showPopup(false);
}
}
}, project.getDisposed());
}
return component;
}
@TestOnly
public boolean isDisposed() {
return myDisposed;
}
@Override
public void dispose() {
ApplicationManager.getApplication().assertIsDispatchThread();
myDisposed = true;
myComponentHint.hide();
myPanel.hide();
if (myOuterComboboxPopupListener != null) {
final Container ancestor = SwingUtilities.getAncestorOfClass(JComboBox.class, myEditor.getContentComponent());
if (ancestor != null) {
((JComboBox)ancestor).removePopupMenuListener(myOuterComboboxPopupListener);
}
myOuterComboboxPopupListener = null;
}
}
@Override
public void editorScrolled() {
closePopup();
}
public boolean isForEditor(@NotNull Editor editor) {
return editor == myEditor;
}
public enum PopupUpdateResult {
NOTHING_CHANGED, // intentions did not change
CHANGED_INVISIBLE, // intentions changed but the popup has not been shown yet, so can recreate list silently
HIDE_AND_RECREATE // ahh, has to close already shown popup, recreate and re-show again
}
//true if actions updated, there is nothing to do
//false if has to recreate popup, no need to reshow
//null if has to reshow
@NotNull
public PopupUpdateResult updateActions(@NotNull ShowIntentionsPass.IntentionsInfo intentions) {
if (myPopup.isDisposed() || !myFile.isValid()) {
return PopupUpdateResult.HIDE_AND_RECREATE;
}
IntentionListStep step = (IntentionListStep)myPopup.getListStep();
if (!step.wrapAndUpdateActions(intentions, true)) {
return PopupUpdateResult.NOTHING_CHANGED;
}
if (!myPopupShown) {
return PopupUpdateResult.CHANGED_INVISIBLE;
}
return PopupUpdateResult.HIDE_AND_RECREATE;
}
@Nullable
@TestOnly
public IntentionAction getAction(int index) {
if (myPopup == null || myPopup.isDisposed()) {
return null;
}
ListPopupStep listStep = myPopup.getListStep();
List<IntentionActionWithTextCaching> values = listStep.getValues();
if (values.size() <= index) {
return null;
}
return values.get(index).getAction();
}
public void recreate() {
ApplicationManager.getApplication().assertIsDispatchThread();
ListPopupStep step = myPopup.getListStep();
recreateMyPopup(step);
}
private void showIntentionHintImpl(final boolean delay, @NotNull Point position) {
final int offset = myEditor.getCaretModel().getOffset();
myComponentHint.setShouldDelay(delay);
HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl();
QuestionAction action = new PriorityQuestionAction() {
@Override
public boolean execute() {
showPopup(false);
return true;
}
@Override
public int getPriority() {
return -10;
}
};
if (hintManager.canShowQuestionAction(action)) {
hintManager.showQuestionHint(myEditor, position, offset, offset, myComponentHint, action, HintManager.ABOVE);
}
}
@NotNull
private static Point getHintPosition(Editor editor) {
if (ApplicationManager.getApplication().isUnitTestMode()) return new Point();
final int offset = editor.getCaretModel().getOffset();
final VisualPosition pos = editor.offsetToVisualPosition(offset);
int line = pos.line;
final Point position = editor.visualPositionToXY(new VisualPosition(line, 0));
LOG.assertTrue(editor.getComponent().isDisplayable());
JComponent convertComponent = editor.getContentComponent();
Point realPoint;
final boolean oneLineEditor = editor.isOneLineMode();
if (oneLineEditor) {
// place bulb at the corner of the surrounding component
final JComponent contentComponent = editor.getContentComponent();
Container ancestorOfClass = SwingUtilities.getAncestorOfClass(JComboBox.class, contentComponent);
if (ancestorOfClass != null) {
convertComponent = (JComponent) ancestorOfClass;
} else {
ancestorOfClass = SwingUtilities.getAncestorOfClass(JTextField.class, contentComponent);
if (ancestorOfClass != null) {
convertComponent = (JComponent) ancestorOfClass;
}
}
realPoint = new Point(- (AllIcons.Actions.RealIntentionBulb.getIconWidth() / 2) - 4, - (AllIcons.Actions.RealIntentionBulb
.getIconHeight() / 2));
} else {
// try to place bulb on the same line
int yShift = -(NORMAL_BORDER_SIZE + AllIcons.Actions.RealIntentionBulb.getIconHeight());
if (canPlaceBulbOnTheSameLine(editor)) {
final int borderHeight = NORMAL_BORDER_SIZE;
yShift = -(borderHeight + (AllIcons.Actions.RealIntentionBulb.getIconHeight() - editor.getLineHeight()) /2 + 3);
}
final int xShift = AllIcons.Actions.RealIntentionBulb.getIconWidth();
Rectangle visibleArea = editor.getScrollingModel().getVisibleArea();
realPoint = new Point(Math.max(0,visibleArea.x - xShift), position.y + yShift);
}
Point location = SwingUtilities.convertPoint(convertComponent, realPoint, editor.getComponent().getRootPane().getLayeredPane());
return new Point(location.x, location.y);
}
private static boolean canPlaceBulbOnTheSameLine(Editor editor) {
if (ApplicationManager.getApplication().isUnitTestMode() || editor.isOneLineMode()) return false;
final int offset = editor.getCaretModel().getOffset();
final VisualPosition pos = editor.offsetToVisualPosition(offset);
int line = pos.line;
final int firstNonSpaceColumnOnTheLine = EditorActionUtil.findFirstNonSpaceColumnOnTheLine(editor, line);
if (firstNonSpaceColumnOnTheLine == -1) return false;
final Point point = editor.visualPositionToXY(new VisualPosition(line, firstNonSpaceColumnOnTheLine));
return point.x > AllIcons.Actions.RealIntentionBulb.getIconWidth() + (editor.isOneLineMode() ? SMALL_BORDER_SIZE : NORMAL_BORDER_SIZE) * 2;
}
private IntentionHintComponent(@NotNull Project project,
@NotNull PsiFile file,
@NotNull final Editor editor,
@NotNull ShowIntentionsPass.IntentionsInfo intentions) {
ApplicationManager.getApplication().assertIsDispatchThread();
myFile = file;
myEditor = editor;
myPanel.setLayout(new BorderLayout());
myPanel.setOpaque(false);
boolean showRefactoringsBulb = ContainerUtil.exists(intentions.inspectionFixesToShow, new Condition<HighlightInfo.IntentionActionDescriptor>() {
@Override
public boolean value(HighlightInfo.IntentionActionDescriptor descriptor) {
return descriptor.getAction() instanceof BaseRefactoringIntentionAction;
}
});
boolean showFix = !showRefactoringsBulb && ContainerUtil.exists(intentions.errorFixesToShow, new Condition<HighlightInfo.IntentionActionDescriptor>() {
@Override
public boolean value(HighlightInfo.IntentionActionDescriptor descriptor) {
return IntentionManagerSettings.getInstance().isShowLightBulb(descriptor.getAction());
}
});
Icon smartTagIcon = showRefactoringsBulb ? AllIcons.Actions.RefactoringBulb : showFix ? AllIcons.Actions.QuickfixBulb : AllIcons.Actions.IntentionBulb;
myHighlightedIcon = new RowIcon(smartTagIcon, AllIcons.General.ArrowDown);
myInactiveIcon = new RowIcon(smartTagIcon, ourInactiveArrowIcon);
myIconLabel = new JLabel(myInactiveIcon);
myIconLabel.setOpaque(false);
myPanel.add(myIconLabel, BorderLayout.CENTER);
myPanel.setBorder(editor.isOneLineMode() ? INACTIVE_BORDER_SMALL : INACTIVE_BORDER);
myIconLabel.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(@NotNull MouseEvent e) {
if (!e.isPopupTrigger() && e.getButton() == MouseEvent.BUTTON1) {
showPopup(true);
}
}
@Override
public void mouseEntered(@NotNull MouseEvent e) {
onMouseEnter(editor.isOneLineMode());
}
@Override
public void mouseExited(@NotNull MouseEvent e) {
onMouseExit(editor.isOneLineMode());
}
});
myComponentHint = new MyComponentHint(myPanel);
ListPopupStep step = new IntentionListStep(this, intentions, myEditor, myFile, project);
recreateMyPopup(step);
// dispose myself when editor closed
EditorFactory.getInstance().addEditorFactoryListener(new EditorFactoryAdapter() {
@Override
public void editorReleased(@NotNull EditorFactoryEvent event) {
if (event.getEditor() == myEditor) {
hide();
}
}
}, this);
}
public void hide() {
Disposer.dispose(this);
}
private void onMouseExit(final boolean small) {
Window ancestor = SwingUtilities.getWindowAncestor(myPopup.getContent());
if (ancestor == null) {
myIconLabel.setIcon(myInactiveIcon);
myPanel.setBorder(small ? INACTIVE_BORDER_SMALL : INACTIVE_BORDER);
}
}
private void onMouseEnter(final boolean small) {
myIconLabel.setIcon(myHighlightedIcon);
myPanel.setBorder(small ? createActiveBorderSmall() : createActiveBorder());
String acceleratorsText = KeymapUtil.getFirstKeyboardShortcutText(
ActionManager.getInstance().getAction(IdeActions.ACTION_SHOW_INTENTION_ACTIONS));
if (!acceleratorsText.isEmpty()) {
myIconLabel.setToolTipText(CodeInsightBundle.message("lightbulb.tooltip", acceleratorsText));
}
}
@TestOnly
public LightweightHint getComponentHint() {
return myComponentHint;
}
private void closePopup() {
ApplicationManager.getApplication().assertIsDispatchThread();
myPopup.cancel();
myPopupShown = false;
}
private void showPopup(boolean mouseClick) {
ApplicationManager.getApplication().assertIsDispatchThread();
if (myPopup == null || myPopup.isDisposed()) return;
if (mouseClick && myPanel.isShowing()) {
final RelativePoint swCorner = RelativePoint.getSouthWestOf(myPanel);
final int yOffset = canPlaceBulbOnTheSameLine(myEditor) ? 0 : myEditor.getLineHeight() - (myEditor.isOneLineMode() ? SMALL_BORDER_SIZE : NORMAL_BORDER_SIZE);
myPopup.show(new RelativePoint(swCorner.getComponent(), new Point(swCorner.getPoint().x, swCorner.getPoint().y + yOffset)));
}
else {
myPopup.showInBestPositionFor(myEditor);
}
myPopupShown = true;
}
private void recreateMyPopup(@NotNull ListPopupStep step) {
ApplicationManager.getApplication().assertIsDispatchThread();
if (myPopup != null) {
Disposer.dispose(myPopup);
}
myPopup = JBPopupFactory.getInstance().createListPopup(step);
if (myPopup instanceof WizardPopup) {
Shortcut[] shortcuts = KeymapManager.getInstance().getActiveKeymap().getShortcuts(IdeActions.ACTION_SHOW_INTENTION_ACTIONS);
for (Shortcut shortcut : shortcuts) {
if (shortcut instanceof KeyboardShortcut) {
KeyboardShortcut keyboardShortcut = (KeyboardShortcut)shortcut;
if (keyboardShortcut.getSecondKeyStroke() == null) {
((WizardPopup)myPopup).registerAction("activateSelectedElement", keyboardShortcut.getFirstKeyStroke(), new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
myPopup.handleSelect(true);
}
});
}
}
}
}
boolean committed = PsiDocumentManager.getInstance(myFile.getProject()).isCommitted(myEditor.getDocument());
final PsiFile injectedFile = committed ? InjectedLanguageUtil.findInjectedPsiNoCommit(myFile, myEditor.getCaretModel().getOffset()) : null;
final Editor injectedEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(myEditor, injectedFile);
final ScopeHighlighter highlighter = new ScopeHighlighter(myEditor);
final ScopeHighlighter injectionHighlighter = new ScopeHighlighter(injectedEditor);
myPopup.addListener(new JBPopupListener.Adapter() {
@Override
public void onClosed(LightweightWindowEvent event) {
highlighter.dropHighlight();
injectionHighlighter.dropHighlight();
myPopupShown = false;
}
});
myPopup.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(@NotNull ListSelectionEvent e) {
final Object source = e.getSource();
highlighter.dropHighlight();
injectionHighlighter.dropHighlight();
if (source instanceof DataProvider) {
final Object selectedItem = PlatformDataKeys.SELECTED_ITEM.getData((DataProvider)source);
if (selectedItem instanceof IntentionActionWithTextCaching) {
final IntentionAction action = ((IntentionActionWithTextCaching)selectedItem).getAction();
if (action instanceof SuppressIntentionActionFromFix) {
if (injectedFile != null && ((SuppressIntentionActionFromFix)action).isShouldBeAppliedToInjectionHost() == ThreeState.NO) {
final PsiElement at = injectedFile.findElementAt(injectedEditor.getCaretModel().getOffset());
final PsiElement container = ((SuppressIntentionActionFromFix)action).getContainer(at);
if (container != null) {
injectionHighlighter.highlight(container, Collections.singletonList(container));
}
}
else {
final PsiElement at = myFile.findElementAt(myEditor.getCaretModel().getOffset());
final PsiElement container = ((SuppressIntentionActionFromFix)action).getContainer(at);
if (container != null) {
highlighter.highlight(container, Collections.singletonList(container));
}
}
}
}
}
}
});
if (myEditor.isOneLineMode()) {
// hide popup on combobox popup show
final Container ancestor = SwingUtilities.getAncestorOfClass(JComboBox.class, myEditor.getContentComponent());
if (ancestor != null) {
final JComboBox comboBox = (JComboBox)ancestor;
myOuterComboboxPopupListener = new PopupMenuListenerAdapter() {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
hide();
}
};
comboBox.addPopupMenuListener(myOuterComboboxPopupListener);
}
}
Disposer.register(this, myPopup);
Disposer.register(myPopup, new Disposable() {
@Override
public void dispose() {
ApplicationManager.getApplication().assertIsDispatchThread();
}
});
}
void canceled(@NotNull ListPopupStep intentionListStep) {
if (myPopup.getListStep() != intentionListStep || myDisposed) {
return;
}
// Root canceled. Create new popup. This one cannot be reused.
recreateMyPopup(intentionListStep);
}
private static class MyComponentHint extends LightweightHint {
private boolean myVisible;
private boolean myShouldDelay;
private MyComponentHint(JComponent component) {
super(component);
}
@Override
public void show(@NotNull final JComponent parentComponent,
final int x,
final int y,
final JComponent focusBackComponent,
@NotNull HintHint hintHint) {
myVisible = true;
if (myShouldDelay) {
myAlarm.cancelAllRequests();
myAlarm.addRequest(new Runnable() {
@Override
public void run() {
showImpl(parentComponent, x, y, focusBackComponent);
}
}, DELAY);
}
else {
showImpl(parentComponent, x, y, focusBackComponent);
}
}
private void showImpl(JComponent parentComponent, int x, int y, JComponent focusBackComponent) {
if (!parentComponent.isShowing()) return;
super.show(parentComponent, x, y, focusBackComponent, new HintHint(parentComponent, new Point(x, y)));
}
@Override
public void hide() {
super.hide();
myVisible = false;
myAlarm.cancelAllRequests();
}
@Override
public boolean isVisible() {
return myVisible || super.isVisible();
}
private void setShouldDelay(boolean shouldDelay) {
myShouldDelay = shouldDelay;
}
}
public static class EnableDisableIntentionAction extends AbstractEditIntentionSettingsAction {
private final IntentionManagerSettings mySettings = IntentionManagerSettings.getInstance();
private final IntentionAction myAction;
public EnableDisableIntentionAction(IntentionAction action) {
super(action);
myAction = action;
// needed for checking errors in user written actions
//noinspection ConstantConditions
LOG.assertTrue(myFamilyName != null, "action "+action.getClass()+" family returned null");
}
@Override
@NotNull
public String getText() {
return mySettings.isEnabled(myAction) ?
CodeInsightBundle.message("disable.intention.action", myFamilyName) :
CodeInsightBundle.message("enable.intention.action", myFamilyName);
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
mySettings.setEnabled(myAction, !mySettings.isEnabled(myAction));
}
@Override
public String toString() {
return getText();
}
}
public static class EditIntentionSettingsAction extends AbstractEditIntentionSettingsAction implements HighPriorityAction {
public EditIntentionSettingsAction(IntentionAction action) {
super(action);
}
@NotNull
@Override
public String getText() {
return "Edit intention settings";
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
final IntentionSettingsConfigurable configurable = new IntentionSettingsConfigurable();
ShowSettingsUtil.getInstance().editConfigurable(project, configurable, new Runnable() {
@Override
public void run() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
configurable.selectIntention(myFamilyName);
}
});
}
});
}
}
private abstract static class AbstractEditIntentionSettingsAction implements IntentionAction {
final String myFamilyName;
private final boolean myDisabled;
private AbstractEditIntentionSettingsAction(IntentionAction action) {
myFamilyName = action.getFamilyName();
myDisabled = action instanceof IntentionActionWrapper &&
Comparing.equal(action.getFamilyName(), ((IntentionActionWrapper)action).getFullFamilyName());
}
@NotNull
@Override
public String getFamilyName() {
return getText();
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return !myDisabled;
}
@Override
public boolean startInWriteAction() {
return false;
}
}
}