All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.intellij.ui.popup.PopupFactoryImpl Maven / Gradle / Ivy

Go to download

A packaging of the IntelliJ Community Edition platform-impl library. This is release number 1 of trunk branch 142.

The newest version!
/*
 * Copyright 2000-2012 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.popup;

import com.intellij.CommonBundle;
import com.intellij.icons.AllIcons;
import com.intellij.ide.DataManager;
import com.intellij.ide.IdeEventQueue;
import com.intellij.ide.IdeTooltipManager;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionUtil;
import com.intellij.openapi.actionSystem.impl.ActionMenu;
import com.intellij.openapi.actionSystem.impl.Utils;
import com.intellij.openapi.application.ex.ApplicationEx;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.VisualPosition;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.popup.*;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.EmptyRunnable;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.openapi.wm.impl.IdeFrameImpl;
import com.intellij.ui.ColorUtil;
import com.intellij.ui.FocusTrackback;
import com.intellij.ui.HintHint;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.ui.popup.list.ListPopupImpl;
import com.intellij.ui.popup.mock.MockConfirmation;
import com.intellij.ui.popup.tree.TreePopupImpl;
import com.intellij.util.PlatformIcons;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.WeakHashMap;
import com.intellij.util.ui.EmptyIcon;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.HyperlinkListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class PopupFactoryImpl extends JBPopupFactory {

  /**
   * Allows to get an editor position for which a popup with auxiliary information might be shown.
   * 

* Primary intention for this key is to hint popup position for the non-caret location. */ public static final Key ANCHOR_POPUP_POSITION = Key.create("popup.anchor.position"); private static final Logger LOG = Logger.getInstance("#com.intellij.ui.popup.PopupFactoryImpl"); private final Map> myStorage = new WeakHashMap>(); @NotNull @Override public ListPopup createConfirmation(String title, final Runnable onYes, int defaultOptionIndex) { return createConfirmation(title, CommonBundle.getYesButtonText(), CommonBundle.getNoButtonText(), onYes, defaultOptionIndex); } @NotNull @Override public ListPopup createConfirmation(String title, final String yesText, String noText, final Runnable onYes, int defaultOptionIndex) { return createConfirmation(title, yesText, noText, onYes, EmptyRunnable.getInstance(), defaultOptionIndex); } @NotNull @Override public JBPopup createMessage(String text) { return createListPopup(new BaseListPopupStep(null, new String[]{text})); } @Override public Balloon getParentBalloonFor(@Nullable Component c) { if (c == null) return null; Component eachParent = c; while (eachParent != null) { if (eachParent instanceof JComponent) { Object balloon = ((JComponent)eachParent).getClientProperty(Balloon.KEY); if (balloon instanceof Balloon) { return (Balloon)balloon; } } eachParent = eachParent.getParent(); } return null; } @NotNull @Override public ListPopup createConfirmation(String title, final String yesText, String noText, final Runnable onYes, final Runnable onNo, int defaultOptionIndex) { final BaseListPopupStep step = new BaseListPopupStep(title, new String[]{yesText, noText}) { @Override public PopupStep onChosen(String selectedValue, final boolean finalChoice) { if (selectedValue.equals(yesText)) { onYes.run(); } else { onNo.run(); } return FINAL_CHOICE; } @Override public void canceled() { onNo.run(); } @Override public boolean isMnemonicsNavigationEnabled() { return true; } }; step.setDefaultOptionIndex(defaultOptionIndex); final ApplicationEx app = ApplicationManagerEx.getApplicationEx(); return app == null || !app.isUnitTestMode() ? new ListPopupImpl(step) : new MockConfirmation(step, yesText); } private static ListPopup createActionGroupPopup(final String title, @NotNull ActionGroup actionGroup, @NotNull DataContext dataContext, boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions, boolean honorActionMnemonics, final Runnable disposeCallback, final int maxRowCount) { return createActionGroupPopup(title, actionGroup, dataContext, showNumbers, useAlphaAsNumbers, showDisabledActions, honorActionMnemonics, disposeCallback, maxRowCount, null, null); } public ListPopup createActionGroupPopup(final String title, final ActionGroup actionGroup, @NotNull DataContext dataContext, boolean showNumbers, boolean showDisabledActions, boolean honorActionMnemonics, final Runnable disposeCallback, final int maxRowCount) { return createActionGroupPopup(title, actionGroup, dataContext, showNumbers, showDisabledActions, honorActionMnemonics, disposeCallback, maxRowCount, null); } private static ListPopup createActionGroupPopup(final String title, @NotNull ActionGroup actionGroup, @NotNull DataContext dataContext, boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions, boolean honorActionMnemonics, final Runnable disposeCallback, final int maxRowCount, final Condition preselectActionCondition, @Nullable final String actionPlace) { return new ActionGroupPopup(title, actionGroup, dataContext, showNumbers, useAlphaAsNumbers, showDisabledActions, honorActionMnemonics, disposeCallback, maxRowCount, preselectActionCondition, actionPlace); } public static class ActionGroupPopup extends ListPopupImpl { private final Runnable myDisposeCallback; private final Component myComponent; public ActionGroupPopup(final String title, @NotNull ActionGroup actionGroup, @NotNull DataContext dataContext, boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions, boolean honorActionMnemonics, final Runnable disposeCallback, final int maxRowCount, final Condition preselectActionCondition, @Nullable final String actionPlace) { super(createStep(title, actionGroup, dataContext, showNumbers, useAlphaAsNumbers, showDisabledActions, honorActionMnemonics, preselectActionCondition, actionPlace), maxRowCount); myDisposeCallback = disposeCallback; myComponent = PlatformDataKeys.CONTEXT_COMPONENT.getData(dataContext); addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { final JList list = (JList)e.getSource(); final ActionItem actionItem = (ActionItem)list.getSelectedValue(); if (actionItem == null) return; AnAction action = actionItem.getAction(); Presentation presentation = new Presentation(); presentation.setDescription(action.getTemplatePresentation().getDescription()); final String actualActionPlace = actionPlace == null ? ActionPlaces.UNKNOWN : actionPlace; final AnActionEvent actionEvent = new AnActionEvent(null, DataManager.getInstance().getDataContext(myComponent), actualActionPlace, presentation, ActionManager.getInstance(), 0); actionEvent.setInjectedContext(action.isInInjectedContext()); ActionUtil.performDumbAwareUpdate(action, actionEvent, false); ActionMenu.showDescriptionInStatusBar(true, myComponent, presentation.getDescription()); } }); } private static ListPopupStep createStep(String title, @NotNull ActionGroup actionGroup, @NotNull DataContext dataContext, boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions, boolean honorActionMnemonics, Condition preselectActionCondition, @Nullable String actionPlace) { final Component component = PlatformDataKeys.CONTEXT_COMPONENT.getData(dataContext); LOG.assertTrue(component != null, "dataContext has no component for new ListPopupStep"); final ActionStepBuilder builder = new ActionStepBuilder(dataContext, showNumbers, useAlphaAsNumbers, showDisabledActions, honorActionMnemonics); if (actionPlace != null) { builder.setActionPlace(actionPlace); } builder.buildGroup(actionGroup); final List items = builder.getItems(); return new ActionPopupStep(items, title, component, showNumbers || honorActionMnemonics && itemsHaveMnemonics(items), preselectActionCondition, false, showDisabledActions); } @Override public void dispose() { if (myDisposeCallback != null) { myDisposeCallback.run(); } ActionMenu.showDescriptionInStatusBar(true, myComponent, null); super.dispose(); } } @NotNull @Override public ListPopup createActionGroupPopup(final String title, @NotNull final ActionGroup actionGroup, @NotNull DataContext dataContext, boolean showNumbers, boolean showDisabledActions, boolean honorActionMnemonics, final Runnable disposeCallback, final int maxRowCount, final Condition preselectActionCondition) { return createActionGroupPopup(title, actionGroup, dataContext, showNumbers, true, showDisabledActions, honorActionMnemonics, disposeCallback, maxRowCount, preselectActionCondition, null); } @NotNull @Override public ListPopup createActionGroupPopup(String title, @NotNull ActionGroup actionGroup, @NotNull DataContext dataContext, ActionSelectionAid selectionAidMethod, boolean showDisabledActions) { return createActionGroupPopup(title, actionGroup, dataContext, selectionAidMethod == ActionSelectionAid.NUMBERING || selectionAidMethod == ActionSelectionAid.ALPHA_NUMBERING, selectionAidMethod == ActionSelectionAid.ALPHA_NUMBERING, showDisabledActions, selectionAidMethod == ActionSelectionAid.MNEMONICS, null, -1); } @NotNull @Override public ListPopup createActionGroupPopup(String title, @NotNull ActionGroup actionGroup, @NotNull DataContext dataContext, ActionSelectionAid selectionAidMethod, boolean showDisabledActions, @Nullable String actionPlace) { return createActionGroupPopup(title, actionGroup, dataContext, selectionAidMethod == ActionSelectionAid.NUMBERING || selectionAidMethod == ActionSelectionAid.ALPHA_NUMBERING, selectionAidMethod == ActionSelectionAid.ALPHA_NUMBERING, showDisabledActions, selectionAidMethod == ActionSelectionAid.MNEMONICS, null, -1, null, actionPlace); } @NotNull @Override public ListPopup createActionGroupPopup(String title, @NotNull ActionGroup actionGroup, @NotNull DataContext dataContext, ActionSelectionAid selectionAidMethod, boolean showDisabledActions, Runnable disposeCallback, int maxRowCount) { return createActionGroupPopup(title, actionGroup, dataContext, selectionAidMethod == ActionSelectionAid.NUMBERING || selectionAidMethod == ActionSelectionAid.ALPHA_NUMBERING, selectionAidMethod == ActionSelectionAid.ALPHA_NUMBERING, showDisabledActions, selectionAidMethod == ActionSelectionAid.MNEMONICS, disposeCallback, maxRowCount); } @NotNull @Override public ListPopupStep createActionsStep(@NotNull final ActionGroup actionGroup, @NotNull DataContext dataContext, final boolean showNumbers, final boolean showDisabledActions, final String title, final Component component, final boolean honorActionMnemonics) { return createActionsStep(actionGroup, dataContext, showNumbers, showDisabledActions, title, component, honorActionMnemonics, 0, false); } private static ListPopupStep createActionsStep(@NotNull ActionGroup actionGroup, @NotNull DataContext dataContext, boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions, String title, Component component, boolean honorActionMnemonics, final int defaultOptionIndex, final boolean autoSelectionEnabled) { final List items = makeActionItemsFromActionGroup(actionGroup, dataContext, showNumbers, useAlphaAsNumbers, showDisabledActions, honorActionMnemonics); return new ActionPopupStep(items, title, component, showNumbers || honorActionMnemonics && itemsHaveMnemonics(items), new Condition() { @Override public boolean value(AnAction action) { return defaultOptionIndex >= 0 && defaultOptionIndex < items.size() && items.get(defaultOptionIndex).getAction().equals(action); } }, autoSelectionEnabled, showDisabledActions); } @NotNull private static List makeActionItemsFromActionGroup(@NotNull ActionGroup actionGroup, @NotNull DataContext dataContext, boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions, boolean honorActionMnemonics) { final ActionStepBuilder builder = new ActionStepBuilder(dataContext, showNumbers, useAlphaAsNumbers, showDisabledActions, honorActionMnemonics); builder.buildGroup(actionGroup); return builder.getItems(); } @NotNull private static ListPopupStep createActionsStep(@NotNull ActionGroup actionGroup, @NotNull DataContext dataContext, boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions, String title, Component component, boolean honorActionMnemonics, Condition preselectActionCondition, boolean autoSelectionEnabled) { final List items = makeActionItemsFromActionGroup(actionGroup, dataContext, showNumbers, useAlphaAsNumbers, showDisabledActions, honorActionMnemonics); return new ActionPopupStep(items, title, component, showNumbers || honorActionMnemonics && itemsHaveMnemonics(items), preselectActionCondition, autoSelectionEnabled, showDisabledActions); } @NotNull @Override public ListPopupStep createActionsStep(@NotNull ActionGroup actionGroup, @NotNull DataContext dataContext, boolean showNumbers, boolean showDisabledActions, String title, Component component, boolean honorActionMnemonics, int defaultOptionIndex, final boolean autoSelectionEnabled) { return createActionsStep(actionGroup, dataContext, showNumbers, true, showDisabledActions, title, component, honorActionMnemonics, defaultOptionIndex, autoSelectionEnabled); } private static boolean itemsHaveMnemonics(final List items) { for (ActionItem item : items) { if (item.getAction().getTemplatePresentation().getMnemonic() != 0) return true; } return false; } @NotNull @Override public ListPopup createWizardStep(@NotNull PopupStep step) { return new ListPopupImpl((ListPopupStep) step); } @NotNull @Override public ListPopup createListPopup(@NotNull ListPopupStep step) { return new ListPopupImpl(step); } @NotNull @Override public ListPopup createListPopup(@NotNull ListPopupStep step, int maxRowCount) { return new ListPopupImpl(step, maxRowCount); } @NotNull @Override public TreePopup createTree(JBPopup parent, @NotNull TreePopupStep aStep, Object parentValue) { return new TreePopupImpl(parent, aStep, parentValue); } @NotNull @Override public TreePopup createTree(@NotNull TreePopupStep aStep) { return new TreePopupImpl(aStep); } @NotNull @Override public ComponentPopupBuilder createComponentPopupBuilder(@NotNull JComponent content, JComponent prefferableFocusComponent) { return new ComponentPopupBuilderImpl(content, prefferableFocusComponent); } @NotNull @Override public RelativePoint guessBestPopupLocation(@NotNull DataContext dataContext) { Component component = PlatformDataKeys.CONTEXT_COMPONENT.getData(dataContext); JComponent focusOwner = component instanceof JComponent ? (JComponent)component : null; if (focusOwner == null) { Project project = CommonDataKeys.PROJECT.getData(dataContext); IdeFrameImpl frame = project == null ? null : ((WindowManagerEx)WindowManager.getInstance()).getFrame(project); focusOwner = frame == null ? null : frame.getRootPane(); if (focusOwner == null) { throw new IllegalArgumentException("focusOwner cannot be null"); } } final Point point = PlatformDataKeys.CONTEXT_MENU_POINT.getData(dataContext); if (point != null) { return new RelativePoint(focusOwner, point); } Editor editor = CommonDataKeys.EDITOR.getData(dataContext); if (editor != null && focusOwner == editor.getContentComponent()) { return guessBestPopupLocation(editor); } else { return guessBestPopupLocation(focusOwner); } } @NotNull @Override public RelativePoint guessBestPopupLocation(@NotNull final JComponent component) { Point popupMenuPoint = null; final Rectangle visibleRect = component.getVisibleRect(); if (component instanceof JList) { // JList JList list = (JList)component; int firstVisibleIndex = list.getFirstVisibleIndex(); int lastVisibleIndex = list.getLastVisibleIndex(); int[] selectedIndices = list.getSelectedIndices(); for (int index : selectedIndices) { if (firstVisibleIndex <= index && index <= lastVisibleIndex) { Rectangle cellBounds = list.getCellBounds(index, index); popupMenuPoint = new Point(visibleRect.x + visibleRect.width / 4, cellBounds.y + cellBounds.height); break; } } } else if (component instanceof JTree) { // JTree JTree tree = (JTree)component; int[] selectionRows = tree.getSelectionRows(); if (selectionRows != null) { Arrays.sort(selectionRows); for (int i = 0; i < selectionRows.length; i++) { int row = selectionRows[i]; Rectangle rowBounds = tree.getRowBounds(row); if (visibleRect.contains(rowBounds)) { popupMenuPoint = new Point(rowBounds.x + 2, rowBounds.y + rowBounds.height - 1); break; } } if (popupMenuPoint == null) {//All selected rows are out of visible rect Point visibleCenter = new Point(visibleRect.x + visibleRect.width / 2, visibleRect.y + visibleRect.height / 2); double minDistance = Double.POSITIVE_INFINITY; int bestRow = -1; Point rowCenter; double distance; for (int i = 0; i < selectionRows.length; i++) { int row = selectionRows[i]; Rectangle rowBounds = tree.getRowBounds(row); rowCenter = new Point(rowBounds.x + rowBounds.width / 2, rowBounds.y + rowBounds.height / 2); distance = visibleCenter.distance(rowCenter); if (minDistance > distance) { minDistance = distance; bestRow = row; } } if (bestRow != -1) { Rectangle rowBounds = tree.getRowBounds(bestRow); tree.scrollRectToVisible(new Rectangle(rowBounds.x, rowBounds.y, Math.min(visibleRect.width, rowBounds.width), rowBounds.height)); popupMenuPoint = new Point(rowBounds.x + 2, rowBounds.y + rowBounds.height - 1); } } } } else if (component instanceof JTable) { JTable table = (JTable)component; int column = table.getColumnModel().getSelectionModel().getLeadSelectionIndex(); int row = Math.max(table.getSelectionModel().getLeadSelectionIndex(), table.getSelectionModel().getAnchorSelectionIndex()); Rectangle rect = table.getCellRect(row, column, false); if (!visibleRect.intersects(rect)) { table.scrollRectToVisible(rect); } popupMenuPoint = new Point(rect.x, rect.y + rect.height); } else if (component instanceof PopupOwner) { popupMenuPoint = ((PopupOwner)component).getBestPopupPosition(); } if (popupMenuPoint == null) { popupMenuPoint = new Point(visibleRect.x + visibleRect.width / 2, visibleRect.y + visibleRect.height / 2); } return new RelativePoint(component, popupMenuPoint); } @Override public boolean isBestPopupLocationVisible(@NotNull Editor editor) { return getVisibleBestPopupLocation(editor) != null; } @NotNull @Override public RelativePoint guessBestPopupLocation(@NotNull Editor editor) { Point p = getVisibleBestPopupLocation(editor); if (p == null) { final Rectangle visibleArea = editor.getScrollingModel().getVisibleArea(); p = new Point(visibleArea.x + visibleArea.width / 3, visibleArea.y + visibleArea.height / 2); } return new RelativePoint(editor.getContentComponent(), p); } @Nullable private static Point getVisibleBestPopupLocation(@NotNull Editor editor) { VisualPosition visualPosition = editor.getUserData(ANCHOR_POPUP_POSITION); if (visualPosition == null) { CaretModel caretModel = editor.getCaretModel(); if (caretModel.isUpToDate()) { visualPosition = caretModel.getVisualPosition(); } else { visualPosition = editor.offsetToVisualPosition(caretModel.getOffset()); } } Point p = editor.visualPositionToXY(new VisualPosition(visualPosition.line + 1, visualPosition.column)); final Rectangle visibleArea = editor.getScrollingModel().getVisibleArea(); return visibleArea.contains(p) ? p : null; } @Override public Point getCenterOf(JComponent container, JComponent content) { return AbstractPopup.getCenterOf(container, content); } public static class ActionItem { private final AnAction myAction; private final String myText; private final boolean myIsEnabled; private final Icon myIcon; private final boolean myPrependWithSeparator; private final String mySeparatorText; private ActionItem(@NotNull AnAction action, @NotNull String text, boolean enabled, Icon icon, final boolean prependWithSeparator, String separatorText) { myAction = action; myText = text; myIsEnabled = enabled; myIcon = icon; myPrependWithSeparator = prependWithSeparator; mySeparatorText = separatorText; } @NotNull public AnAction getAction() { return myAction; } @NotNull public String getText() { return myText; } public Icon getIcon() { return myIcon; } public boolean isPrependWithSeparator() { return myPrependWithSeparator; } public String getSeparatorText() { return mySeparatorText; } public boolean isEnabled() { return myIsEnabled; } } private static class ActionPopupStep implements ListPopupStepEx, MnemonicNavigationFilter, SpeedSearchFilter { private final List myItems; private final String myTitle; private final Component myContext; private final boolean myEnableMnemonics; private final int myDefaultOptionIndex; private final boolean myAutoSelectionEnabled; private final boolean myShowDisabledActions; private Runnable myFinalRunnable; @Nullable private final Condition myPreselectActionCondition; private ActionPopupStep(@NotNull final List items, final String title, Component context, boolean enableMnemonics, @Nullable Condition preselectActionCondition, final boolean autoSelection, boolean showDisabledActions) { myItems = items; myTitle = title; myContext = context; myEnableMnemonics = enableMnemonics; myDefaultOptionIndex = getDefaultOptionIndexFromSelectCondition(preselectActionCondition, items); myPreselectActionCondition = preselectActionCondition; myAutoSelectionEnabled = autoSelection; myShowDisabledActions = showDisabledActions; } private static int getDefaultOptionIndexFromSelectCondition(@Nullable Condition preselectActionCondition, @NotNull List items) { int defaultOptionIndex = 0; if (preselectActionCondition != null) { for (int i = 0; i < items.size(); i++) { final AnAction action = items.get(i).getAction(); if (preselectActionCondition.value(action)) { defaultOptionIndex = i; break; } } } return defaultOptionIndex; } @Override @NotNull public List getValues() { return myItems; } @Override public boolean isSelectable(final ActionItem value) { return value.isEnabled(); } @Override public int getMnemonicPos(final ActionItem value) { final String text = getTextFor(value); int i = text.indexOf(UIUtil.MNEMONIC); if (i < 0) { i = text.indexOf('&'); } if (i < 0) { i = text.indexOf('_'); } return i; } @Override public Icon getIconFor(final ActionItem aValue) { return aValue.getIcon(); } @Override @NotNull public String getTextFor(final ActionItem value) { return value.getText(); } @Override public ListSeparator getSeparatorAbove(final ActionItem value) { return value.isPrependWithSeparator() ? new ListSeparator(value.getSeparatorText()) : null; } @Override public int getDefaultOptionIndex() { return myDefaultOptionIndex; } @Override public String getTitle() { return myTitle; } @Override public PopupStep onChosen(final ActionItem actionChoice, final boolean finalChoice) { return onChosen(actionChoice, finalChoice, 0); } @Override public PopupStep onChosen(ActionItem actionChoice, boolean finalChoice, final int eventModifiers) { if (!actionChoice.isEnabled()) return FINAL_CHOICE; final AnAction action = actionChoice.getAction(); DataManager mgr = DataManager.getInstance(); final DataContext dataContext = myContext != null ? mgr.getDataContext(myContext) : mgr.getDataContext(); if (action instanceof ActionGroup && (!finalChoice || !((ActionGroup)action).canBePerformed(dataContext))) { return createActionsStep((ActionGroup)action, dataContext, myEnableMnemonics, true, myShowDisabledActions, null, myContext, false, myPreselectActionCondition, false); } else { myFinalRunnable = new Runnable() { @Override public void run() { final AnActionEvent event = new AnActionEvent(null, dataContext, ActionPlaces.UNKNOWN, action.getTemplatePresentation().clone(), ActionManager.getInstance(), eventModifiers); event.setInjectedContext(action.isInInjectedContext()); if (ActionUtil.lastUpdateAndCheckDumb(action, event, false)) { action.actionPerformed(event); } } }; return FINAL_CHOICE; } } @Override public Runnable getFinalRunnable() { return myFinalRunnable; } @Override public boolean hasSubstep(final ActionItem selectedValue) { return selectedValue != null && selectedValue.isEnabled() && selectedValue.getAction() instanceof ActionGroup; } @Override public void canceled() { } @Override public boolean isMnemonicsNavigationEnabled() { return myEnableMnemonics; } @Override public MnemonicNavigationFilter getMnemonicNavigationFilter() { return this; } @Override public boolean canBeHidden(final ActionItem value) { return true; } @Override public String getIndexedString(final ActionItem value) { return getTextFor(value); } @Override public boolean isSpeedSearchEnabled() { return true; } @Override public boolean isAutoSelectionEnabled() { return myAutoSelectionEnabled; } @Override public SpeedSearchFilter getSpeedSearchFilter() { return this; } } @Override @NotNull public List getChildPopups(@NotNull final Component component) { return FocusTrackback.getChildPopups(component); } @Override public boolean isPopupActive() { return IdeEventQueue.getInstance().isPopupActive(); } private static class ActionStepBuilder { private final List myListModel; private final DataContext myDataContext; private final boolean myShowNumbers; private final boolean myUseAlphaAsNumbers; private final boolean myShowDisabled; private final HashMap myAction2presentation; private int myCurrentNumber; private boolean myPrependWithSeparator; private String mySeparatorText; private final boolean myHonorActionMnemonics; private Icon myEmptyIcon; private int myMaxIconWidth = -1; private int myMaxIconHeight = -1; @NotNull private String myActionPlace; private ActionStepBuilder(@NotNull DataContext dataContext, final boolean showNumbers, final boolean useAlphaAsNumbers, final boolean showDisabled, final boolean honorActionMnemonics) { myUseAlphaAsNumbers = useAlphaAsNumbers; myListModel = new ArrayList(); myDataContext = dataContext; myShowNumbers = showNumbers; myShowDisabled = showDisabled; myAction2presentation = new HashMap(); myCurrentNumber = 0; myPrependWithSeparator = false; mySeparatorText = null; myHonorActionMnemonics = honorActionMnemonics; myActionPlace = ActionPlaces.UNKNOWN; } public void setActionPlace(@NotNull String actionPlace) { myActionPlace = actionPlace; } @NotNull public List getItems() { return myListModel; } public void buildGroup(@NotNull ActionGroup actionGroup) { calcMaxIconSize(actionGroup); myEmptyIcon = myMaxIconHeight != -1 && myMaxIconWidth != -1 ? new EmptyIcon(myMaxIconWidth, myMaxIconHeight) : null; appendActionsFromGroup(actionGroup); if (myListModel.isEmpty()) { myListModel.add(new ActionItem(Utils.EMPTY_MENU_FILLER, Utils.NOTHING_HERE, false, null, false, null)); } } private void calcMaxIconSize(final ActionGroup actionGroup) { AnAction[] actions = actionGroup.getChildren(createActionEvent(actionGroup)); for (AnAction action : actions) { if (action == null) continue; if (action instanceof ActionGroup) { final ActionGroup group = (ActionGroup)action; if (!group.isPopup()) { calcMaxIconSize(group); continue; } } Icon icon = action.getTemplatePresentation().getIcon(); if (icon == null && action instanceof Toggleable) icon = PlatformIcons.CHECK_ICON; if (icon != null) { final int width = icon.getIconWidth(); final int height = icon.getIconHeight(); if (myMaxIconWidth < width) { myMaxIconWidth = width; } if (myMaxIconHeight < height) { myMaxIconHeight = height; } } } } @NotNull private AnActionEvent createActionEvent(@NotNull AnAction actionGroup) { final AnActionEvent actionEvent = new AnActionEvent(null, myDataContext, myActionPlace, getPresentation(actionGroup), ActionManager.getInstance(), 0); actionEvent.setInjectedContext(actionGroup.isInInjectedContext()); return actionEvent; } private void appendActionsFromGroup(@NotNull ActionGroup actionGroup) { AnAction[] actions = actionGroup.getChildren(createActionEvent(actionGroup)); for (AnAction action : actions) { if (action == null) { LOG.error("null action in group " + actionGroup); continue; } if (action instanceof Separator) { myPrependWithSeparator = true; mySeparatorText = ((Separator)action).getText(); } else { if (action instanceof ActionGroup) { ActionGroup group = (ActionGroup)action; if (group.isPopup()) { appendAction(group); } else { appendActionsFromGroup(group); } } else { appendAction(action); } } } } private void appendAction(@NotNull AnAction action) { Presentation presentation = getPresentation(action); AnActionEvent event = createActionEvent(action); ActionUtil.performDumbAwareUpdate(action, event, true); if ((myShowDisabled || presentation.isEnabled()) && presentation.isVisible()) { String text = presentation.getText(); if (myShowNumbers) { if (myCurrentNumber < 9) { text = "&" + (myCurrentNumber + 1) + ". " + text; } else if (myCurrentNumber == 9) { text = "&" + 0 + ". " + text; } else if (myUseAlphaAsNumbers) { text = "&" + (char)('A' + myCurrentNumber - 10) + ". " + text; } myCurrentNumber++; } else if (myHonorActionMnemonics) { text = Presentation.restoreTextWithMnemonic(text, action.getTemplatePresentation().getMnemonic()); } Icon icon = presentation.isEnabled() ? presentation.getIcon() : IconLoader.getDisabledIcon(presentation.getIcon()); if (icon == null) { @NonNls final String actionId = ActionManager.getInstance().getId(action); if (actionId != null && actionId.startsWith("QuickList.")) { icon = AllIcons.Actions.QuickList; } else if (action instanceof Toggleable) { boolean toggled = Boolean.TRUE.equals(presentation.getClientProperty(Toggleable.SELECTED_PROPERTY)); icon = toggled? new IconWrapper(PlatformIcons.CHECK_ICON) : myEmptyIcon; } else { icon = myEmptyIcon; } } else { icon = new IconWrapper(icon); } boolean prependSeparator = (!myListModel.isEmpty() || mySeparatorText != null) && myPrependWithSeparator; assert text != null : action + " has no presentation"; myListModel.add(new ActionItem(action, text, presentation.isEnabled(), icon, prependSeparator, mySeparatorText)); myPrependWithSeparator = false; mySeparatorText = null; } } /** * Adjusts icon size to maximum, so that icons with different sizes were aligned correctly. */ private class IconWrapper implements Icon { private Icon myIcon; IconWrapper(Icon icon) { myIcon = icon; } @Override public void paintIcon(Component c, Graphics g, int x, int y) { myIcon.paintIcon(c, g, x, y); } @Override public int getIconWidth() { return myMaxIconWidth; } @Override public int getIconHeight() { return myMaxIconHeight; } } private Presentation getPresentation(@NotNull AnAction action) { Presentation presentation = myAction2presentation.get(action); if (presentation == null) { presentation = action.getTemplatePresentation().clone(); myAction2presentation.put(action, presentation); } return presentation; } } @NotNull @Override public BalloonBuilder createBalloonBuilder(@NotNull final JComponent content) { return new BalloonPopupBuilderImpl(myStorage, content); } @NotNull @Override public BalloonBuilder createDialogBalloonBuilder(@NotNull JComponent content, String title) { final BalloonPopupBuilderImpl builder = new BalloonPopupBuilderImpl(myStorage, content); final Color bg = UIManager.getColor("Panel.background"); final Color borderOriginal = Color.darkGray; final Color border = ColorUtil.toAlpha(borderOriginal, 75); builder .setDialogMode(true) .setTitle(title) .setAnimationCycle(200) .setFillColor(bg) .setBorderColor(border) .setHideOnClickOutside(false) .setHideOnKeyOutside(false) .setHideOnAction(false) .setCloseButtonEnabled(true) .setShadow(true); return builder; } @NotNull @Override public BalloonBuilder createHtmlTextBalloonBuilder(@NotNull final String htmlContent, @Nullable final Icon icon, final Color fillColor, @Nullable final HyperlinkListener listener) { JEditorPane text = IdeTooltipManager.initPane(htmlContent, new HintHint().setAwtTooltip(true), null); if (listener != null) { text.addHyperlinkListener(listener); } text.setEditable(false); NonOpaquePanel.setTransparent(text); text.setBorder(null); JLabel label = new JLabel(); final JPanel content = new NonOpaquePanel(new BorderLayout((int)(label.getIconTextGap() * 1.5), (int)(label.getIconTextGap() * 1.5))); final NonOpaquePanel textWrapper = new NonOpaquePanel(new GridBagLayout()); JScrollPane scrolledText = new JScrollPane(text); scrolledText.setBackground(fillColor); scrolledText.getViewport().setBackground(fillColor); scrolledText.getViewport().setBorder(null); scrolledText.setBorder(null); textWrapper.add(scrolledText); content.add(textWrapper, BorderLayout.CENTER); final NonOpaquePanel north = new NonOpaquePanel(new BorderLayout()); north.add(new JLabel(icon), BorderLayout.NORTH); content.add(north, BorderLayout.WEST); content.setBorder(new EmptyBorder(2, 4, 2, 4)); final BalloonBuilder builder = createBalloonBuilder(content); builder.setFillColor(fillColor); return builder; } @NotNull @Override public BalloonBuilder createHtmlTextBalloonBuilder(@NotNull String htmlContent, MessageType messageType, @Nullable HyperlinkListener listener) { return createHtmlTextBalloonBuilder(htmlContent, messageType.getDefaultIcon(), messageType.getPopupBackground(), listener); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy