// calculates average of the median values in the selected part of the array. E.g. for part=3
 // returns average in the middle third.
 public static long averageAmongMedians(@NotNull long[] time, int part) {
   assert part >= 1;
   int n = time.length;
   Arrays.sort(time);
   long total = 0;
   for (int i = n / 2 - n / part / 2; i < n / 2 + n / part / 2; i++) {
     total += time[i];
   }
   return total / (n / part);
 }
  @Override
  public void actionPerformed(AnActionEvent e) {
    final List<Descriptor> descriptors = new ArrayList<Descriptor>();
    final InspectionConfigTreeNode[] selectedNodes =
        myTree.getSelectedNodes(InspectionConfigTreeNode.class, null);
    LOG.assertTrue(selectedNodes != null);

    final List<InspectionConfigTreeNode> nodes =
        new ArrayList<InspectionConfigTreeNode>(Arrays.asList(selectedNodes));
    for (InspectionConfigTreeNode node : selectedNodes) {
      collect(descriptors, nodes, node);
    }

    final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
    final List<String> availableScopes = getAvailableScopes(project, descriptors);
    final int idx =
        Messages.showChooseDialog(
            myTree,
            "Scope:",
            "Choose Scope",
            ArrayUtil.toStringArray(availableScopes),
            availableScopes.get(0),
            Messages.getQuestionIcon());
    if (idx == -1) return;
    final NamedScope chosenScope = NamedScopesHolder.getScope(project, availableScopes.get(idx));

    for (InspectionConfigTreeNode node : nodes) {
      final Descriptor descriptor = node.getDesriptor();
      if (node.getScopeName() != null || descriptor == null) continue;
      final InspectionProfileEntry tool = descriptor.getTool(); // copy
      final ScopeToolState scopeToolState =
          getSelectedProfile()
              .addScope(
                  tool,
                  chosenScope,
                  getSelectedProfile().getErrorLevel(descriptor.getKey(), chosenScope),
                  getSelectedProfile().isToolEnabled(descriptor.getKey()));
      final Descriptor addedDescriptor = new Descriptor(scopeToolState, getSelectedProfile());
      if (node.getChildCount() == 0) {
        node.add(
            new InspectionConfigTreeNode(
                descriptor,
                getSelectedProfile().getToolDefaultState(descriptor.getKey().toString()),
                true,
                true,
                false));
      }
      node.insert(new InspectionConfigTreeNode(addedDescriptor, scopeToolState, false, false), 0);
      node.setInspectionNode(false);
      node.dropCache();
      ((DefaultTreeModel) myTree.getModel()).reload(node);
      myTree.expandPath(new TreePath(node.getPath()));
    }
    myTree.revalidate();
  }
 private static int[] findAvailablePorts(Project project, PyConsoleType consoleType) {
   final int[] ports;
   try {
     // File "pydev/console/pydevconsole.py", line 223, in <module>
     // port, client_port = sys.argv[1:3]
     ports = NetUtils.findAvailableSocketPorts(2);
   } catch (IOException e) {
     ExecutionHelper.showErrors(
         project, Arrays.<Exception>asList(e), consoleType.getTitle(), null);
     return null;
   }
   return ports;
 }
  protected void showDiffForChanges(Change[] changesArray, final int indexInSelection) {
    final ShowDiffContext context =
        new ShowDiffContext(isInFrame() ? DiffDialogHints.FRAME : DiffDialogHints.MODAL);

    context.addActions(createDiffActions());
    if (myDiffBottomComponent != null) {
      context.putChainContext(DiffUserDataKeysEx.BOTTOM_PANEL, myDiffBottomComponent);
    }

    updateDiffContext(context);

    ShowDiffAction.showDiffForChange(
        myProject, Arrays.asList(changesArray), indexInSelection, context);
  }
 public Collection<AbstractVcs> getAffectedVcses() {
   final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(myProject);
   final Set<AbstractVcs> vcses =
       new HashSet<AbstractVcs>(Arrays.asList(vcsManager.getAllActiveVcss()));
   final Set<AbstractVcs> result = new HashSet<AbstractVcs>();
   for (Change change : myBrowser.myAllChanges) {
     if (vcses.isEmpty()) break;
     final AbstractVcs vcs = ChangesUtil.getVcsForChange(change, myBrowser.myProject);
     if (vcs != null) {
       result.add(vcs);
       vcses.remove(vcs);
     }
   }
   return result;
 }
  private void recalculateIconRenderersWidth() {
    myLineToRenderersMap.clear();
    for (EditorMessageIconRenderer renderer : myIconRenderers) {
      int yCoordinate = getIconCoordinate(renderer);
      if (yCoordinate < 0) {
        continue;
      }
      List<IconRendererLayoutConstraint> renderersForLine = myLineToRenderersMap.get(yCoordinate);
      if (renderersForLine == null) {
        renderersForLine = new SortedList(myIconRenderersComparator);
        myLineToRenderersMap.put(yCoordinate, renderersForLine);
      }
      renderersForLine.add(new IconRendererLayoutConstraint(renderer));
    }

    myIconRenderersWidth = MIN_ICON_RENDERERS_WIDTH;
    myMaxIconHeight = 0;
    int[] sortedYCoordinates = myLineToRenderersMap.keys();
    Arrays.sort(sortedYCoordinates);

    int initialOffset = getIconRenderersOffset();
    for (int y : sortedYCoordinates) {
      List<IconRendererLayoutConstraint> row = myLineToRenderersMap.get(y);
      assert row.size() != 0;
      int maxIconHeight = 0;
      for (IconRendererLayoutConstraint rendererConstraint : row) {
        maxIconHeight =
            Math.max(maxIconHeight, rendererConstraint.getIconRenderer().getIcon().getIconHeight());
      }
      myMaxIconHeight = Math.max(myMaxIconHeight, maxIconHeight);
      int offset = initialOffset + LEFT_GAP;
      for (Iterator<IconRendererLayoutConstraint> it = row.iterator(); it.hasNext(); ) {
        IconRendererLayoutConstraint rendererConstraint = it.next();
        rendererConstraint.setX(offset);
        offset += rendererConstraint.getIconRenderer().getIcon().getIconWidth();
        if (it.hasNext()) {
          offset += GAP_BETWEEN_ICONS;
        }
      }
      myIconRenderersWidth = Math.max(myIconRenderersWidth, offset - initialOffset);
    }
  }
  private static int doPrint(
      StringBuilder buffer,
      int currentLevel,
      Object node,
      AbstractTreeStructure structure,
      @Nullable Comparator comparator,
      int maxRowCount,
      int currentLine,
      char paddingChar,
      @Nullable Queryable.PrintInfo printInfo) {
    if (currentLine >= maxRowCount && maxRowCount != -1) return currentLine;

    StringUtil.repeatSymbol(buffer, paddingChar, currentLevel);
    buffer.append(toString(node, printInfo)).append("\n");
    currentLine++;
    Object[] children = structure.getChildElements(node);

    if (comparator != null) {
      ArrayList<?> list = new ArrayList<Object>(Arrays.asList(children));
      @SuppressWarnings({"UnnecessaryLocalVariable", "unchecked"})
      Comparator<Object> c = comparator;
      Collections.sort(list, c);
      children = ArrayUtil.toObjectArray(list);
    }
    for (Object child : children) {
      currentLine =
          doPrint(
              buffer,
              currentLevel + 1,
              child,
              structure,
              comparator,
              maxRowCount,
              currentLine,
              paddingChar,
              printInfo);
    }

    return currentLine;
  }
  private static JBPopup getPsiElementPopup(
      final Object[] elements,
      final Map<PsiElement, GotoRelatedItem> itemsMap,
      final String title,
      final Processor<Object> processor) {

    final Ref<Boolean> hasMnemonic = Ref.create(false);
    final DefaultPsiElementCellRenderer renderer =
        new DefaultPsiElementCellRenderer() {
          {
            setFocusBorderEnabled(false);
          }

          @Override
          public String getElementText(PsiElement element) {
            String customName = itemsMap.get(element).getCustomName();
            return (customName != null ? customName : super.getElementText(element));
          }

          @Override
          protected Icon getIcon(PsiElement element) {
            Icon customIcon = itemsMap.get(element).getCustomIcon();
            return customIcon != null ? customIcon : super.getIcon(element);
          }

          @Override
          public String getContainerText(PsiElement element, String name) {
            PsiFile file = element.getContainingFile();
            return file != null && !getElementText(element).equals(file.getName())
                ? "(" + file.getName() + ")"
                : null;
          }

          @Override
          protected DefaultListCellRenderer getRightCellRenderer() {
            return null;
          }

          @Override
          protected boolean customizeNonPsiElementLeftRenderer(
              ColoredListCellRenderer renderer,
              JList list,
              Object value,
              int index,
              boolean selected,
              boolean hasFocus) {
            final GotoRelatedItem item = (GotoRelatedItem) value;
            Color color = list.getForeground();
            final SimpleTextAttributes nameAttributes = new SimpleTextAttributes(Font.PLAIN, color);
            final String name = item.getCustomName();
            if (name == null) return false;
            renderer.append(name, nameAttributes);
            renderer.setIcon(item.getCustomIcon());
            return true;
          }

          @Override
          public Component getListCellRendererComponent(
              JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            final JPanel component =
                (JPanel)
                    super.getListCellRendererComponent(
                        list, value, index, isSelected, cellHasFocus);
            if (!hasMnemonic.get()) return component;

            final JPanel panelWithMnemonic = new JPanel(new BorderLayout());
            final int mnemonic = getMnemonic(value, itemsMap);
            final JLabel label = new JLabel("");
            if (mnemonic != -1) {
              label.setText(mnemonic + ".");
              label.setDisplayedMnemonicIndex(0);
            }
            label.setPreferredSize(new JLabel("8.").getPreferredSize());

            final JComponent leftRenderer = (JComponent) component.getComponents()[0];
            component.remove(leftRenderer);
            panelWithMnemonic.setBackground(leftRenderer.getBackground());
            label.setBackground(leftRenderer.getBackground());
            panelWithMnemonic.add(label, BorderLayout.WEST);
            panelWithMnemonic.add(leftRenderer, BorderLayout.CENTER);
            component.add(panelWithMnemonic);
            return component;
          }
        };
    final ListPopupImpl popup =
        new ListPopupImpl(
            new BaseListPopupStep<Object>(title, Arrays.asList(elements)) {
              @Override
              public boolean isSpeedSearchEnabled() {
                return true;
              }

              @Override
              public PopupStep onChosen(Object selectedValue, boolean finalChoice) {
                processor.process(selectedValue);
                return super.onChosen(selectedValue, finalChoice);
              }
            }) {
          @Override
          protected ListCellRenderer getListElementRenderer() {
            return renderer;
          }
        };
    popup.setMinimumSize(new Dimension(200, -1));
    for (Object item : elements) {
      final int mnemonic = getMnemonic(item, itemsMap);
      if (mnemonic != -1) {
        final Action action = createNumberAction(mnemonic, popup, itemsMap, processor);
        popup.registerAction(
            mnemonic + "Action", KeyStroke.getKeyStroke(String.valueOf(mnemonic)), action);
        hasMnemonic.set(true);
      }
    }
    return popup;
  }
 @Override
 public boolean equals(final BaseInjection o1, final BaseInjection o2) {
   return o1.sameLanguageParameters(o2)
       && Arrays.equals(o1.getInjectionPlaces(), o2.getInjectionPlaces());
 }
  @Override
  @NotNull
  public AnAction[] getChildren(@Nullable AnActionEvent e) {
    FileTemplateManager manager = FileTemplateManager.getInstance();
    FileTemplate[] templates = manager.getAllTemplates();

    boolean showAll = templates.length <= FileTemplateManager.RECENT_TEMPLATES_SIZE;
    if (!showAll) {
      Collection<String> recentNames = manager.getRecentNames();
      templates = new FileTemplate[recentNames.size()];
      int i = 0;
      for (String name : recentNames) {
        templates[i] = FileTemplateManager.getInstance().getTemplate(name);
        i++;
      }
    }

    Arrays.sort(
        templates,
        new Comparator<FileTemplate>() {
          @Override
          public int compare(FileTemplate template1, FileTemplate template2) {
            // java first
            if (template1.isTemplateOfType(InternalStdFileTypes.JAVA)
                && !template2.isTemplateOfType(InternalStdFileTypes.JAVA)) {
              return -1;
            }
            if (template2.isTemplateOfType(InternalStdFileTypes.JAVA)
                && !template1.isTemplateOfType(InternalStdFileTypes.JAVA)) {
              return 1;
            }

            // group by type
            int i = template1.getExtension().compareTo(template2.getExtension());
            if (i != 0) {
              return i;
            }

            // group by name if same type
            return template1.getName().compareTo(template2.getName());
          }
        });
    List<AnAction> result = new ArrayList<AnAction>();

    for (FileTemplate template : templates) {
      if (canCreateFromTemplate(e, template)) {
        AnAction action = replaceAction(template);
        if (action == null) {
          action = new CreateFromTemplateAction(template);
        }
        result.add(action);
      }
    }

    if (!result.isEmpty()) {
      if (!showAll) {
        result.add(new CreateFromTemplatesAction(IdeBundle.message("action.from.file.template")));
      }

      result.add(AnSeparator.getInstance());
      result.add(new EditFileTemplatesAction(IdeBundle.message("action.edit.file.templates")));
    }

    return result.toArray(new AnAction[result.size()]);
  }
/**
 * This class is automaton with finite number of state.
 *
 * @author Anton Katilin
 * @author Vladimir Kondratyev
 */
public final class IdeKeyEventDispatcher implements Disposable {
  @NonNls private static final String GET_CACHED_STROKE_METHOD_NAME = "getCachedStroke";

  private KeyStroke myFirstKeyStroke;
  /**
   * When we "dispatch" key event via keymap, i.e. when registered action has been executed instead
   * of event dispatching, then we have to consume all following KEY_RELEASED and KEY_TYPED event
   * because they are not valid.
   */
  private boolean myPressedWasProcessed;

  private KeyState myState = KeyState.STATE_INIT;

  private final PresentationFactory myPresentationFactory = new PresentationFactory();
  private boolean myDisposed = false;
  private boolean myLeftCtrlPressed = false;
  private boolean myRightAltPressed = false;

  private final KeyboardGestureProcessor myKeyGestureProcessor = new KeyboardGestureProcessor(this);

  private final KeyProcessorContext myContext = new KeyProcessorContext();
  private final IdeEventQueue myQueue;

  private final Alarm mySecondStrokeTimeout = new Alarm();
  private final Runnable mySecondStrokeTimeoutRunnable =
      new Runnable() {
        public void run() {
          if (myState == KeyState.STATE_WAIT_FOR_SECOND_KEYSTROKE) {
            resetState();
            if (myContext != null) {
              final DataContext dataContext = myContext.getDataContext();
              StatusBar.Info.set(
                  null, dataContext == null ? null : PlatformDataKeys.PROJECT.getData(dataContext));
            }
          }
        }
      };

  private final Alarm mySecondKeystrokePopupTimeout = new Alarm();

  public IdeKeyEventDispatcher(IdeEventQueue queue) {
    myQueue = queue;
    Application parent =
        ApplicationManager
            .getApplication(); // Application is null on early start when e.g. license dialog is
    // shown
    if (parent != null) Disposer.register(parent, this);
  }

  public boolean isWaitingForSecondKeyStroke() {
    return getState() == KeyState.STATE_WAIT_FOR_SECOND_KEYSTROKE || isPressedWasProcessed();
  }

  /**
   * @return <code>true</code> if and only if the passed event is already dispatched by the <code>
   *     IdeKeyEventDispatcher</code> and there is no need for any other processing of the event.
   */
  public boolean dispatchKeyEvent(final KeyEvent e) {
    if (myDisposed) return false;

    if (e.isConsumed()) {
      return false;
    }

    // http://www.jetbrains.net/jira/browse/IDEADEV-12372
    if (e.getKeyCode() == KeyEvent.VK_CONTROL) {
      if (e.getID() == KeyEvent.KEY_PRESSED) {
        myLeftCtrlPressed = e.getKeyLocation() == KeyEvent.KEY_LOCATION_LEFT;
      } else if (e.getID() == KeyEvent.KEY_RELEASED) {
        myLeftCtrlPressed = false;
      }
    } else if (e.getKeyCode() == KeyEvent.VK_ALT) {
      if (e.getID() == KeyEvent.KEY_PRESSED) {
        myRightAltPressed = e.getKeyLocation() == KeyEvent.KEY_LOCATION_RIGHT;
      } else if (e.getID() == KeyEvent.KEY_RELEASED) {
        myRightAltPressed = false;
      }
    }

    KeyboardFocusManager focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
    Component focusOwner = focusManager.getFocusOwner();

    // shortcuts should not work in shortcut setup fields
    if (focusOwner instanceof ShortcutTextField) {
      return false;
    }
    if (focusOwner instanceof JTextComponent && ((JTextComponent) focusOwner).isEditable()) {
      if (e.getKeyChar() != KeyEvent.CHAR_UNDEFINED && e.getKeyChar() != KeyEvent.VK_ESCAPE) {
        MacUIUtil.hideCursor();
      }
    }

    MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager();
    MenuElement[] selectedPath = menuSelectionManager.getSelectedPath();
    if (selectedPath.length > 0) {
      if (!(selectedPath[0] instanceof ComboPopup)) {
        // The following couple of lines of code is a PATCH!!!
        // It is needed to ignore ENTER KEY_TYPED events which sometimes can reach editor when an
        // action
        // is invoked from main menu via Enter key.
        setState(KeyState.STATE_PROCESSED);
        setPressedWasProcessed(true);
        return false;
      }
    }

    // Keymap shortcuts (i.e. not local shortcuts) should work only in:
    // - main frame
    // - floating focusedWindow
    // - when there's an editor in contexts
    Window focusedWindow = focusManager.getFocusedWindow();
    boolean isModalContext = focusedWindow != null && isModalContext(focusedWindow);

    final DataManager dataManager = DataManager.getInstance();
    if (dataManager == null) return false;

    DataContext dataContext = dataManager.getDataContext();

    myContext.setDataContext(dataContext);
    myContext.setFocusOwner(focusOwner);
    myContext.setModalContext(isModalContext);
    myContext.setInputEvent(e);

    try {
      if (getState() == KeyState.STATE_INIT) {
        return inInitState();
      } else if (getState() == KeyState.STATE_PROCESSED) {
        return inProcessedState();
      } else if (getState() == KeyState.STATE_WAIT_FOR_SECOND_KEYSTROKE) {
        return inWaitForSecondStrokeState();
      } else if (getState() == KeyState.STATE_SECOND_STROKE_IN_PROGRESS) {
        return inSecondStrokeInProgressState();
      } else if (getState() == KeyState.STATE_KEY_GESTURE_PROCESSOR) {
        return myKeyGestureProcessor.process();
      } else {
        throw new IllegalStateException("state = " + getState());
      }
    } finally {
      myContext.clear();
    }
  }

  /**
   * @return <code>true</code> if and only if the <code>component</code> represents modal context.
   * @throws IllegalArgumentException if <code>component</code> is <code>null</code>.
   */
  public static boolean isModalContext(@NotNull Component component) {
    Window window;
    if (component instanceof Window) {
      window = (Window) component;
    } else {
      window = SwingUtilities.getWindowAncestor(component);
    }

    if (window instanceof IdeFrameImpl) {
      final Component pane = ((IdeFrameImpl) window).getGlassPane();
      if (pane instanceof IdeGlassPaneEx) {
        return ((IdeGlassPaneEx) pane).isInModalContext();
      }
    }

    if (window instanceof JDialog) {
      final JDialog dialog = (JDialog) window;
      if (!dialog.isModal()) {
        return isModalContext(dialog.getOwner());
      }
    }

    if (window instanceof JFrame) {
      return false;
    }

    boolean isMainFrame = window instanceof IdeFrameImpl;
    boolean isFloatingDecorator = window instanceof FloatingDecorator;

    boolean isPopup = !(component instanceof JFrame) && !(component instanceof JDialog);
    if (isPopup) {
      if (component instanceof JWindow) {
        JBPopup popup =
            (JBPopup) ((JWindow) component).getRootPane().getClientProperty(AbstractPopup.KEY);
        if (popup != null) {
          return popup.isModalContext();
        }
      }
    }

    return !isMainFrame && !isFloatingDecorator;
  }

  private boolean inWaitForSecondStrokeState() {
    // a key pressed means that the user starts to enter the second stroke...
    if (KeyEvent.KEY_PRESSED == myContext.getInputEvent().getID()) {
      setState(KeyState.STATE_SECOND_STROKE_IN_PROGRESS);
      return inSecondStrokeInProgressState();
    }
    // looks like RELEASEs (from the first stroke) go here...  skip them
    return true;
  }

  /**
   * This is hack. AWT doesn't allow to create KeyStroke with specified key code and key char
   * simultaneously. Therefore we are using reflection.
   */
  private static KeyStroke getKeyStrokeWithoutMouseModifiers(KeyStroke originalKeyStroke) {
    int modifier =
        originalKeyStroke.getModifiers()
            & ~InputEvent.BUTTON1_DOWN_MASK
            & ~InputEvent.BUTTON1_MASK
            & ~InputEvent.BUTTON2_DOWN_MASK
            & ~InputEvent.BUTTON2_MASK
            & ~InputEvent.BUTTON3_DOWN_MASK
            & ~InputEvent.BUTTON3_MASK;
    try {
      Method[] methods = AWTKeyStroke.class.getDeclaredMethods();
      Method getCachedStrokeMethod = null;
      for (Method method : methods) {
        if (GET_CACHED_STROKE_METHOD_NAME.equals(method.getName())) {
          getCachedStrokeMethod = method;
          getCachedStrokeMethod.setAccessible(true);
          break;
        }
      }
      if (getCachedStrokeMethod == null) {
        throw new IllegalStateException("not found method with name getCachedStrokeMethod");
      }
      Object[] getCachedStrokeMethodArgs =
          new Object[] {
            originalKeyStroke.getKeyChar(),
            originalKeyStroke.getKeyCode(),
            modifier,
            originalKeyStroke.isOnKeyRelease()
          };
      return (KeyStroke) getCachedStrokeMethod.invoke(originalKeyStroke, getCachedStrokeMethodArgs);
    } catch (Exception exc) {
      throw new IllegalStateException(exc.getMessage());
    }
  }

  private boolean inSecondStrokeInProgressState() {
    KeyEvent e = myContext.getInputEvent();

    // when any key is released, we stop waiting for the second stroke
    if (KeyEvent.KEY_RELEASED == e.getID()) {
      myFirstKeyStroke = null;
      setState(KeyState.STATE_INIT);
      Project project = PlatformDataKeys.PROJECT.getData(myContext.getDataContext());
      StatusBar.Info.set(null, project);
      return false;
    }

    KeyStroke originalKeyStroke = KeyStroke.getKeyStrokeForEvent(e);
    KeyStroke keyStroke = getKeyStrokeWithoutMouseModifiers(originalKeyStroke);

    updateCurrentContext(
        myContext.getFoundComponent(),
        new KeyboardShortcut(myFirstKeyStroke, keyStroke),
        myContext.isModalContext());

    // consume the wrong second stroke and keep on waiting
    if (myContext.getActions().isEmpty()) {
      return true;
    }

    // finally user had managed to enter the second keystroke, so let it be processed
    Project project = PlatformDataKeys.PROJECT.getData(myContext.getDataContext());
    StatusBarEx statusBar = (StatusBarEx) WindowManager.getInstance().getStatusBar(project);
    if (processAction(e, myActionProcessor)) {
      if (statusBar != null) {
        statusBar.setInfo(null);
      }
      return true;
    } else {
      return false;
    }
  }

  private boolean inProcessedState() {
    KeyEvent e = myContext.getInputEvent();

    // ignore typed events which come after processed pressed event
    if (KeyEvent.KEY_TYPED == e.getID() && isPressedWasProcessed()) {
      return true;
    }
    if (KeyEvent.KEY_RELEASED == e.getID()
        && KeyEvent.VK_ALT == e.getKeyCode()
        && isPressedWasProcessed()) {
      // see IDEADEV-8615
      return true;
    }
    setState(KeyState.STATE_INIT);
    setPressedWasProcessed(false);
    return inInitState();
  }

  private static final Set<String> ALT_GR_LAYOUTS =
      new HashSet<String>(
          Arrays.asList(
              "pl", "de", "fi", "fr", "no", "da", "se", "pt", "nl", "tr", "sl", "hu", "bs", "hr",
              "sr", "sk", "lv"));

  private boolean inInitState() {
    Component focusOwner = myContext.getFocusOwner();
    boolean isModalContext = myContext.isModalContext();
    DataContext dataContext = myContext.getDataContext();
    KeyEvent e = myContext.getInputEvent();

    // http://www.jetbrains.net/jira/browse/IDEADEV-12372
    if (myLeftCtrlPressed
        && myRightAltPressed
        && focusOwner != null
        && e.getModifiers() == (InputEvent.CTRL_MASK | InputEvent.ALT_MASK)) {
      if (Registry.is("actionSystem.force.alt.gr")) {
        return false;
      }
      final InputContext inputContext = focusOwner.getInputContext();
      if (inputContext != null) {
        Locale locale = inputContext.getLocale();
        if (locale != null) {
          @NonNls final String language = locale.getLanguage();
          if (ALT_GR_LAYOUTS.contains(language)) {
            // don't search for shortcuts
            return false;
          }
        }
      }
    }

    KeyStroke originalKeyStroke = KeyStroke.getKeyStrokeForEvent(e);
    KeyStroke keyStroke = getKeyStrokeWithoutMouseModifiers(originalKeyStroke);

    if (myKeyGestureProcessor.processInitState()) {
      return true;
    }

    if (SystemInfo.isMac) {
      boolean keyTyped = e.getID() == KeyEvent.KEY_TYPED;
      boolean hasMnemonicsInWindow =
          e.getID() == KeyEvent.KEY_PRESSED && hasMnemonicInWindow(focusOwner, e.getKeyCode())
              || keyTyped && hasMnemonicInWindow(focusOwner, e.getKeyChar());
      boolean imEnabled = IdeEventQueue.getInstance().isInputMethodEnabled();

      if (e.getModifiersEx() == InputEvent.ALT_DOWN_MASK
          && (hasMnemonicsInWindow || (!imEnabled && keyTyped))) {
        setPressedWasProcessed(true);
        setState(KeyState.STATE_PROCESSED);
        return false;
      }
    }

    updateCurrentContext(focusOwner, new KeyboardShortcut(keyStroke, null), isModalContext);
    if (myContext.getActions().isEmpty()) {
      // there's nothing mapped for this stroke
      return false;
    }

    if (myContext.isHasSecondStroke()) {
      myFirstKeyStroke = keyStroke;
      final ArrayList<Pair<AnAction, KeyStroke>> secondKeyStrokes = getSecondKeystrokeActions();

      final Project project = PlatformDataKeys.PROJECT.getData(dataContext);
      StringBuilder message = new StringBuilder();
      message.append(KeyMapBundle.message("prefix.key.pressed.message"));
      message.append(' ');
      for (int i = 0; i < secondKeyStrokes.size(); i++) {
        Pair<AnAction, KeyStroke> pair = secondKeyStrokes.get(i);
        if (i > 0) message.append(", ");
        message.append(pair.getFirst().getTemplatePresentation().getText());
        message.append(" (");
        message.append(KeymapUtil.getKeystrokeText(pair.getSecond()));
        message.append(")");
      }

      StatusBar.Info.set(message.toString(), project);

      mySecondStrokeTimeout.cancelAllRequests();
      mySecondStrokeTimeout.addRequest(
          mySecondStrokeTimeoutRunnable, Registry.intValue("actionSystem.secondKeystrokeTimeout"));

      if (Registry.is("actionSystem.secondKeystrokeAutoPopupEnabled")) {
        mySecondKeystrokePopupTimeout.cancelAllRequests();
        if (secondKeyStrokes.size() > 1) {
          final DataContext oldContext = myContext.getDataContext();
          mySecondKeystrokePopupTimeout.addRequest(
              new Runnable() {
                @Override
                public void run() {
                  if (myState == KeyState.STATE_WAIT_FOR_SECOND_KEYSTROKE) {
                    StatusBar.Info.set(null, PlatformDataKeys.PROJECT.getData(oldContext));
                    new SecondaryKeystrokePopup(myFirstKeyStroke, secondKeyStrokes, oldContext)
                        .showInBestPositionFor(oldContext);
                  }
                }
              },
              Registry.intValue("actionSystem.secondKeystrokePopupTimeout"));
        }
      }

      setState(KeyState.STATE_WAIT_FOR_SECOND_KEYSTROKE);
      return true;
    } else {
      return processAction(e, myActionProcessor);
    }
  }

  private ArrayList<Pair<AnAction, KeyStroke>> getSecondKeystrokeActions() {
    ArrayList<Pair<AnAction, KeyStroke>> secondKeyStrokes =
        new ArrayList<Pair<AnAction, KeyStroke>>();
    for (AnAction action : myContext.getActions()) {
      Shortcut[] shortcuts = action.getShortcutSet().getShortcuts();
      for (Shortcut shortcut : shortcuts) {
        if (shortcut instanceof KeyboardShortcut) {
          KeyboardShortcut keyShortcut = (KeyboardShortcut) shortcut;
          if (keyShortcut.getFirstKeyStroke().equals(myFirstKeyStroke)) {
            secondKeyStrokes.add(
                new Pair<AnAction, KeyStroke>(action, keyShortcut.getSecondKeyStroke()));
          }
        }
      }
    }
    return secondKeyStrokes;
  }

  private static boolean hasMnemonicInWindow(Component focusOwner, int keyCode) {
    if (keyCode == KeyEvent.VK_ALT || keyCode == 0) return false; // Optimization
    final Container container = getContainer(focusOwner);
    return hasMnemonic(container, keyCode) || hasMnemonicInBalloons(container, keyCode);
  }

  @Nullable
  private static Container getContainer(@Nullable final Component focusOwner) {
    if (focusOwner == null) return null;
    if (focusOwner.isLightweight()) {
      Container container = focusOwner.getParent();
      while (container != null) {
        final Container parent = container.getParent();
        if (parent instanceof JLayeredPane) break;
        if (parent != null && parent.isLightweight()) {
          container = parent;
        } else {
          break;
        }
      }
      return container;
    }

    return SwingUtilities.windowForComponent(focusOwner);
  }

  private static boolean hasMnemonic(final Container container, final int keyCode) {
    if (container == null) return false;

    final Component[] components = container.getComponents();
    for (Component component : components) {
      if (component instanceof AbstractButton) {
        final AbstractButton button = (AbstractButton) component;
        if (button instanceof JBOptionButton) {
          if (((JBOptionButton) button).isOkToProcessDefaultMnemonics()) return true;
        } else {
          if (button.getMnemonic() == keyCode) return true;
        }
      }
      if (component instanceof JLabel) {
        final JLabel label = (JLabel) component;
        if (label.getDisplayedMnemonic() == keyCode) return true;
      }
      if (component instanceof Container) {
        if (hasMnemonic((Container) component, keyCode)) return true;
      }
    }
    return false;
  }

  private static boolean hasMnemonicInBalloons(Container container, int code) {
    final Component parent = UIUtil.findUltimateParent(container);
    if (parent instanceof RootPaneContainer) {
      final JLayeredPane pane = ((RootPaneContainer) parent).getLayeredPane();
      for (Component component : pane.getComponents()) {
        if (component instanceof ComponentWithMnemonics
            && component instanceof Container
            && hasMnemonic((Container) component, code)) {
          return true;
        }
      }
    }
    return false;
  }

  private final ActionProcessor myActionProcessor =
      new ActionProcessor() {
        public AnActionEvent createEvent(
            final InputEvent inputEvent,
            final DataContext context,
            final String place,
            final Presentation presentation,
            final ActionManager manager) {
          return new AnActionEvent(inputEvent, context, place, presentation, manager, 0);
        }

        public void onUpdatePassed(
            final InputEvent inputEvent, final AnAction action, final AnActionEvent actionEvent) {
          setState(KeyState.STATE_PROCESSED);
          setPressedWasProcessed(inputEvent.getID() == KeyEvent.KEY_PRESSED);
        }

        public void performAction(
            final InputEvent e, final AnAction action, final AnActionEvent actionEvent) {
          e.consume();
          action.actionPerformed(actionEvent);
          if (Registry.is("actionSystem.fixLostTyping")) {
            IdeEventQueue.getInstance()
                .doWhenReady(
                    new Runnable() {
                      @Override
                      public void run() {
                        IdeEventQueue.getInstance().getKeyEventDispatcher().resetState();
                      }
                    });
          }
        }
      };

  public boolean processAction(final InputEvent e, ActionProcessor processor) {
    ActionManagerEx actionManager = ActionManagerEx.getInstanceEx();
    final Project project = PlatformDataKeys.PROJECT.getData(myContext.getDataContext());
    final boolean dumb = project != null && DumbService.getInstance(project).isDumb();
    List<AnActionEvent> nonDumbAwareAction = new ArrayList<AnActionEvent>();
    for (final AnAction action : myContext.getActions()) {
      final Presentation presentation = myPresentationFactory.getPresentation(action);

      // Mouse modifiers are 0 because they have no any sense when action is invoked via keyboard
      final AnActionEvent actionEvent =
          processor.createEvent(
              e,
              myContext.getDataContext(),
              ActionPlaces.MAIN_MENU,
              presentation,
              ActionManager.getInstance());

      ActionUtil.performDumbAwareUpdate(action, actionEvent, true);

      if (dumb && !action.isDumbAware()) {
        if (Boolean.FALSE.equals(
            presentation.getClientProperty(ActionUtil.WOULD_BE_ENABLED_IF_NOT_DUMB_MODE))) {
          continue;
        }

        nonDumbAwareAction.add(actionEvent);
        continue;
      }

      if (!presentation.isEnabled()) {
        continue;
      }

      processor.onUpdatePassed(e, action, actionEvent);

      ((DataManagerImpl.MyDataContext) myContext.getDataContext())
          .setEventCount(IdeEventQueue.getInstance().getEventCount(), this);
      actionManager.fireBeforeActionPerformed(action, actionEvent.getDataContext(), actionEvent);
      Component component =
          PlatformDataKeys.CONTEXT_COMPONENT.getData(actionEvent.getDataContext());
      if (component != null && !component.isShowing()) {
        return true;
      }

      processor.performAction(e, action, actionEvent);
      actionManager.fireAfterActionPerformed(action, actionEvent.getDataContext(), actionEvent);
      return true;
    }

    if (!nonDumbAwareAction.isEmpty()) {
      showDumbModeWarningLaterIfNobodyConsumesEvent(
          e, nonDumbAwareAction.toArray(new AnActionEvent[nonDumbAwareAction.size()]));
    }

    return false;
  }

  private static void showDumbModeWarningLaterIfNobodyConsumesEvent(
      final InputEvent e, final AnActionEvent... actionEvents) {
    if (ModalityState.current() == ModalityState.NON_MODAL) {
      ApplicationManager.getApplication()
          .invokeLater(
              new Runnable() {
                public void run() {
                  if (e.isConsumed()) return;

                  ActionUtil.showDumbModeWarning(actionEvents);
                }
              });
    }
  }

  /**
   * This method fills <code>myActions</code> list.
   *
   * @return true if there is a shortcut with second stroke found.
   */
  public KeyProcessorContext updateCurrentContext(
      Component component, Shortcut sc, boolean isModalContext) {
    myContext.setFoundComponent(null);
    myContext.getActions().clear();

    if (isControlEnterOnDialog(component, sc)) return myContext;

    boolean hasSecondStroke = false;

    // here we try to find "local" shortcuts

    for (; component != null; component = component.getParent()) {
      if (!(component instanceof JComponent)) {
        continue;
      }
      ArrayList listOfActions =
          (ArrayList) ((JComponent) component).getClientProperty(AnAction.ourClientProperty);
      if (listOfActions == null) {
        continue;
      }
      for (Object listOfAction : listOfActions) {
        if (!(listOfAction instanceof AnAction)) {
          continue;
        }
        AnAction action = (AnAction) listOfAction;
        hasSecondStroke |= addAction(action, sc);
      }
      // once we've found a proper local shortcut(s), we continue with non-local shortcuts
      if (!myContext.getActions().isEmpty()) {
        myContext.setFoundComponent((JComponent) component);
        break;
      }
    }

    // search in main keymap

    Keymap keymap = KeymapManager.getInstance().getActiveKeymap();
    String[] actionIds = keymap.getActionIds(sc);

    ActionManager actionManager = ActionManager.getInstance();
    for (String actionId : actionIds) {
      AnAction action = actionManager.getAction(actionId);
      if (action != null) {
        if (isModalContext && !action.isEnabledInModalContext()) {
          continue;
        }
        hasSecondStroke |= addAction(action, sc);
      }
    }

    if (!hasSecondStroke && sc instanceof KeyboardShortcut) {
      // little trick to invoke action which second stroke is a key w/o modifiers, but user still
      // holds the modifier key(s) of the first stroke

      final KeyboardShortcut keyboardShortcut = (KeyboardShortcut) sc;
      final KeyStroke firstKeyStroke = keyboardShortcut.getFirstKeyStroke();
      final KeyStroke secondKeyStroke = keyboardShortcut.getSecondKeyStroke();

      if (secondKeyStroke != null
          && secondKeyStroke.getModifiers() != 0
          && firstKeyStroke.getModifiers() != 0) {
        final KeyboardShortcut altShortCut =
            new KeyboardShortcut(
                firstKeyStroke, KeyStroke.getKeyStroke(secondKeyStroke.getKeyCode(), 0));
        final String[] additionalActions = keymap.getActionIds(altShortCut);

        for (final String actionId : additionalActions) {
          AnAction action = actionManager.getAction(actionId);
          if (action != null) {
            if (isModalContext && !action.isEnabledInModalContext()) {
              continue;
            }
            hasSecondStroke |= addAction(action, altShortCut);
          }
        }
      }
    }

    myContext.setHasSecondStroke(hasSecondStroke);

    Comparator<? super AnAction> comparator =
        PlatformDataKeys.ACTIONS_SORTER.getData(myContext.getDataContext());
    if (comparator != null) {
      Collections.sort(myContext.getActions(), comparator);
    }

    return myContext;
  }

  private static KeyboardShortcut CONTROL_ENTER = KeyboardShortcut.fromString("control ENTER");

  private static boolean isControlEnterOnDialog(Component component, Shortcut sc) {
    return CONTROL_ENTER.equals(sc)
        && !IdeEventQueue.getInstance().isPopupActive() // avoid Control+Enter in completion
        && DialogWrapper.findInstance(component) != null;
  }

  /** @return true if action is added and has second stroke */
  private boolean addAction(AnAction action, Shortcut sc) {
    boolean hasSecondStroke = false;

    Shortcut[] shortcuts = action.getShortcutSet().getShortcuts();
    for (Shortcut each : shortcuts) {
      if (!each.isKeyboard()) continue;

      if (each.startsWith(sc)) {
        if (!myContext.getActions().contains(action)) {
          myContext.getActions().add(action);
        }

        if (each instanceof KeyboardShortcut) {
          hasSecondStroke |= ((KeyboardShortcut) each).getSecondKeyStroke() != null;
        }
      }
    }

    return hasSecondStroke;
  }

  public KeyProcessorContext getContext() {
    return myContext;
  }

  public void dispose() {
    myDisposed = true;
  }

  public KeyState getState() {
    return myState;
  }

  public void setState(final KeyState state) {
    myState = state;
    if (myQueue != null) {
      myQueue.maybeReady();
    }
  }

  public void resetState() {
    setState(KeyState.STATE_INIT);
    setPressedWasProcessed(false);
  }

  public boolean isPressedWasProcessed() {
    return myPressedWasProcessed;
  }

  public void setPressedWasProcessed(boolean pressedWasProcessed) {
    myPressedWasProcessed = pressedWasProcessed;
  }

  public boolean isReady() {
    return myState == KeyState.STATE_INIT || myState == KeyState.STATE_PROCESSED;
  }

  private static class SecondaryKeystrokePopup extends ListPopupImpl {
    private SecondaryKeystrokePopup(
        @NotNull final KeyStroke firstKeystroke,
        @NotNull final List<Pair<AnAction, KeyStroke>> actions,
        final DataContext context) {
      super(buildStep(actions, context));
      registerActions(firstKeystroke, actions, context);
    }

    private void registerActions(
        @NotNull final KeyStroke firstKeyStroke,
        @NotNull final List<Pair<AnAction, KeyStroke>> actions,
        final DataContext ctx) {
      ContainerUtil.process(
          actions,
          new Processor<Pair<AnAction, KeyStroke>>() {
            @Override
            public boolean process(final Pair<AnAction, KeyStroke> pair) {
              final String actionText = pair.getFirst().getTemplatePresentation().getText();
              final AbstractAction a =
                  new AbstractAction() {
                    @Override
                    public void actionPerformed(final ActionEvent e) {
                      cancel();
                      invokeAction(pair.getFirst(), ctx);
                    }
                  };

              final KeyStroke keyStroke = pair.getSecond();
              registerAction(actionText, keyStroke, a);

              if (keyStroke.getModifiers() == 0) {
                // do a little trick here, so if I will press Command+R and the second keystroke is
                // just 'R',
                // I want to be able to hold the Command while pressing 'R'

                final KeyStroke additionalKeyStroke =
                    KeyStroke.getKeyStroke(keyStroke.getKeyCode(), firstKeyStroke.getModifiers());
                final String _existing = getActionForKeyStroke(additionalKeyStroke);
                if (_existing == null)
                  registerAction("__additional__" + actionText, additionalKeyStroke, a);
              }

              return true;
            }
          });
    }

    private static void invokeAction(@NotNull final AnAction action, final DataContext ctx) {
      ApplicationManager.getApplication()
          .invokeLater(
              new Runnable() {
                @Override
                public void run() {
                  final AnActionEvent event =
                      new AnActionEvent(
                          null,
                          ctx,
                          ActionPlaces.UNKNOWN,
                          (Presentation) action.getTemplatePresentation().clone(),
                          ActionManager.getInstance(),
                          0);
                  if (ActionUtil.lastUpdateAndCheckDumb(action, event, true)) {
                    action.actionPerformed(event);
                  }
                }
              });
    }

    @Override
    protected ListCellRenderer getListElementRenderer() {
      return new ActionListCellRenderer();
    }

    private static ListPopupStep buildStep(
        @NotNull final List<Pair<AnAction, KeyStroke>> actions, final DataContext ctx) {
      return new BaseListPopupStep<Pair<AnAction, KeyStroke>>(
          "Choose an action",
          ContainerUtil.findAll(
              actions,
              new Condition<Pair<AnAction, KeyStroke>>() {
                @Override
                public boolean value(Pair<AnAction, KeyStroke> pair) {
                  final AnAction action = pair.getFirst();
                  final Presentation presentation =
                      (Presentation) action.getTemplatePresentation().clone();
                  AnActionEvent event =
                      new AnActionEvent(
                          null,
                          ctx,
                          ActionPlaces.UNKNOWN,
                          presentation,
                          ActionManager.getInstance(),
                          0);

                  ActionUtil.performDumbAwareUpdate(action, event, true);
                  return presentation.isEnabled() && presentation.isVisible();
                }
              })) {
        @Override
        public PopupStep onChosen(Pair<AnAction, KeyStroke> selectedValue, boolean finalChoice) {
          invokeAction(selectedValue.getFirst(), ctx);
          return FINAL_CHOICE;
        }
      };
    }

    private static class ActionListCellRenderer extends ColoredListCellRenderer {
      @Override
      protected void customizeCellRenderer(
          final JList list,
          final Object value,
          final int index,
          final boolean selected,
          final boolean hasFocus) {
        if (value == null) return;
        if (value instanceof Pair) {
          final Pair<AnAction, KeyStroke> pair = (Pair<AnAction, KeyStroke>) value;
          append(
              KeymapUtil.getShortcutText(new KeyboardShortcut(pair.getSecond(), null)),
              SimpleTextAttributes.GRAY_ATTRIBUTES);
          appendAlign(30);
          final String text = pair.getFirst().getTemplatePresentation().getText();
          append(text, SimpleTextAttributes.REGULAR_ATTRIBUTES);
        }
      }
    }
  }
}
 public static String print(Object[] objects) {
   return print(Arrays.asList(objects));
 }