private void showCompletionPopup(
      final CompletionResult result, int position, boolean isExplicit) {
    if (myList == null) {
      myList = new JBList();
      myList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

      myList.setCellRenderer(
          new GroupedItemsListRenderer(
              new ListItemDescriptor() {
                public String getTextFor(final Object value) {
                  final LookupFile file = (LookupFile) value;

                  if (file.getMacro() != null) {
                    return file.getMacro();
                  } else {
                    return (myCurrentCompletion != null
                                && myCurrentCompletion.myKidsAfterSeparator.contains(file)
                            ? myFinder.getSeparator()
                            : "")
                        + file.getName();
                  }
                }

                public String getTooltipFor(final Object value) {
                  return null;
                }

                public Icon getIconFor(final Object value) {
                  final LookupFile file = (LookupFile) value;
                  return file.getIcon();
                }

                @Nullable
                private Separator getSeparatorAboveOf(Object value) {
                  if (myCurrentCompletion == null) return null;
                  final LookupFile file = (LookupFile) value;

                  final int fileIndex = myCurrentCompletion.myToComplete.indexOf(file);
                  if (fileIndex > 0 && !myCurrentCompletion.myMacros.contains(file)) {
                    final LookupFile prev = myCurrentCompletion.myToComplete.get(fileIndex - 1);
                    if (myCurrentCompletion.myMacros.contains(prev)) {
                      return new Separator("");
                    }
                  }

                  if (myCurrentCompletion.myKidsAfterSeparator.indexOf(file) == 0
                      && myCurrentCompletion.mySiblings.size() > 0) {
                    final LookupFile parent = file.getParent();
                    return parent == null ? new Separator("") : new Separator(parent.getName());
                  }

                  if (myCurrentCompletion.myMacros.size() > 0 && fileIndex == 0) {
                    return new Separator(
                        IdeBundle.message("file.chooser.completion.path.variables.text"));
                  }

                  return null;
                }

                public boolean hasSeparatorAboveOf(final Object value) {
                  return getSeparatorAboveOf(value) != null;
                }

                public String getCaptionAboveOf(final Object value) {
                  final FileTextFieldImpl.Separator separator = getSeparatorAboveOf(value);
                  return separator != null ? separator.getText() : null;
                }
              }));
    }

    if (myCurrentPopup != null) {
      closePopup();
    }

    myCurrentCompletion = result;
    myCurrentCompletionsPos = position;

    if (myCurrentCompletion.myToComplete.size() == 0) {
      showNoSuggestions(isExplicit);
      return;
    }

    myList.setModel(
        new AbstractListModel() {
          public int getSize() {
            return myCurrentCompletion.myToComplete.size();
          }

          public Object getElementAt(final int index) {
            return myCurrentCompletion.myToComplete.get(index);
          }
        });
    myList.getSelectionModel().clearSelection();
    final PopupChooserBuilder builder = JBPopupFactory.getInstance().createListPopupBuilder(myList);
    builder.addListener(
        new JBPopupListener() {
          public void beforeShown(LightweightWindowEvent event) {
            myPathTextField.registerKeyboardAction(
                myCancelAction,
                KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
                JComponent.WHEN_IN_FOCUSED_WINDOW);
            for (Action each : myDisabledTextActions) {
              each.setEnabled(false);
            }
          }

          public void onClosed(LightweightWindowEvent event) {
            myPathTextField.unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0));
            for (Action each : myDisabledTextActions) {
              each.setEnabled(true);
            }
          }
        });

    myCurrentPopup =
        builder
            .setRequestFocus(false)
            .setAdText(getAdText(myCurrentCompletion))
            .setAutoSelectIfEmpty(false)
            .setResizable(false)
            .setCancelCallback(
                new Computable<Boolean>() {
                  public Boolean compute() {
                    final int caret = myPathTextField.getCaretPosition();
                    myPathTextField.setSelectionStart(caret);
                    myPathTextField.setSelectionEnd(caret);
                    myPathTextField.setFocusTraversalKeysEnabled(true);
                    SwingUtilities.invokeLater(
                        new Runnable() {
                          public void run() {
                            getField().requestFocus();
                          }
                        });
                    return Boolean.TRUE;
                  }
                })
            .setItemChoosenCallback(
                new Runnable() {
                  public void run() {
                    processChosenFromCompletion(false);
                  }
                })
            .setCancelKeyEnabled(false)
            .setAlpha(0.1f)
            .setFocusOwners(new Component[] {myPathTextField})
            .createPopup();

    if (result.myPreselected != null) {
      myList.setSelectedValue(result.myPreselected, false);
    }

    myPathTextField.setFocusTraversalKeysEnabled(false);

    myCurrentPopup.showInScreenCoordinates(getField(), getLocationForCaret(myPathTextField));
  }
  /**
   * Initialize the frame.
   *
   * @param info true if additional information is desired
   */
  private void init(boolean info) {
    _buttonPressed = null;
    addComponentListener(
        new java.awt.event.ComponentAdapter() {
          public void componentResized(ComponentEvent e) {
            validate();
            _matchList.ensureIndexIsVisible(_matchList.getSelectedIndex());
          }
        });

    // buttons
    int i = 0;
    for (final CloseAction<T> a : _actions) {
      _buttons[i] = new JButton(a.getName());
      final String tooltip = a.getToolTipText();
      if (tooltip != null) {
        _buttons[i].setToolTipText(tooltip);
      }
      _buttons[i].addActionListener(
          new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              buttonPressed(a);
            }
          });
      ++i;
    }

    getRootPane().setDefaultButton(_buttons[0]);

    _strategyBox.setEditable(false);
    _strategyBox.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            // System.out.println("set strategy!");
            selectStrategy();
          }
        });
    _strategyBox.addFocusListener(
        new FocusAdapter() {

          public void focusLost(FocusEvent e) {
            boolean bf = false;
            for (JButton b : _buttons) {
              if (e.getOppositeComponent() == b) {
                bf = true;
                break;
              }
            }
            if ((e.getOppositeComponent() != _textField) && (!bf)) {
              for (JComponent c : _optionalComponents) {
                if (e.getOppositeComponent() == c) {
                  return;
                }
              }
              _textField.requestFocus();
            }
          }
        });

    // text field
    _textField.setDragEnabled(false);
    _textField.setFocusTraversalKeysEnabled(false);

    addListener();

    Keymap ourMap =
        JTextComponent.addKeymap("PredictiveInputFrame._textField", _textField.getKeymap());
    for (final CloseAction<T> a : _actions) {
      KeyStroke ks = a.getKeyStroke();
      if (ks != null) {
        ourMap.addActionForKeyStroke(
            ks,
            new AbstractAction() {
              public void actionPerformed(ActionEvent e) {
                buttonPressed(a);
              }
            });
      }
    }
    ourMap.addActionForKeyStroke(
        KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0),
        new AbstractAction() {
          public void actionPerformed(ActionEvent e) {
            //        System.out.println("tab!");
            removeListener();
            _pim.extendSharedMask();
            updateTextField();
            updateExtensionLabel();
            updateList();
            addListener();
          }
        });
    ourMap.addActionForKeyStroke(
        KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),
        new AbstractAction() {
          public void actionPerformed(ActionEvent e) {
            //        System.out.println("up!");
            if (_matchList.getModel().getSize() > 0) {
              removeListener();
              int i = _matchList.getSelectedIndex();
              if (i > 0) {
                _matchList.setSelectedIndex(i - 1);
                _matchList.ensureIndexIsVisible(i - 1);
                _pim.setCurrentItem(_pim.getMatchingItems().get(i - 1));
                updateInfo();
              }
              addListener();
            }
          }
        });
    ourMap.addActionForKeyStroke(
        KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),
        new AbstractAction() {
          public void actionPerformed(ActionEvent e) {
            //        System.out.println("down!");
            if (_matchList.getModel().getSize() > 0) {
              removeListener();
              int i = _matchList.getSelectedIndex();
              if (i < _matchList.getModel().getSize() - 1) {
                _matchList.setSelectedIndex(i + 1);
                _matchList.ensureIndexIsVisible(i + 1);
                _pim.setCurrentItem(_pim.getMatchingItems().get(i + 1));
                updateInfo();
              }
              addListener();
            }
          }
        });
    ourMap.addActionForKeyStroke(
        KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0),
        new AbstractAction() {
          public void actionPerformed(ActionEvent e) {
            //        System.out.println("page up!");
            if (_matchList.getModel().getSize() > 0) {
              removeListener();
              int page = _matchList.getLastVisibleIndex() - _matchList.getFirstVisibleIndex() + 1;
              int i = _matchList.getSelectedIndex() - page;
              if (i < 0) i = 0;
              _matchList.setSelectedIndex(i);
              _matchList.ensureIndexIsVisible(i);
              _pim.setCurrentItem(_pim.getMatchingItems().get(i));
              updateInfo();
              addListener();
            }
          }
        });
    ourMap.addActionForKeyStroke(
        KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0),
        new AbstractAction() {
          public void actionPerformed(ActionEvent e) {
            //        System.out.println("page down!");
            if (_matchList.getModel().getSize() > 0) {
              removeListener();
              int page = _matchList.getLastVisibleIndex() - _matchList.getFirstVisibleIndex() + 1;
              int i = _matchList.getSelectedIndex() + page;
              if (i >= _matchList.getModel().getSize()) {
                i = _matchList.getModel().getSize() - 1;
              }
              _matchList.setSelectedIndex(i);
              _matchList.ensureIndexIsVisible(i);
              _pim.setCurrentItem(_pim.getMatchingItems().get(i));
              updateInfo();
              addListener();
            }
          }
        });
    _textField.setKeymap(ourMap);

    _textField.addFocusListener(
        new FocusAdapter() {
          public void focusLost(FocusEvent e) {
            boolean bf = false;
            for (JButton b : _buttons) {
              if (e.getOppositeComponent() == b) {
                bf = true;
                break;
              }
            }
            if ((e.getOppositeComponent() != _strategyBox) && (!bf)) {
              for (JComponent c : _optionalComponents) {
                if (e.getOppositeComponent() == c) {
                  return;
                }
              }
              _textField.requestFocus();
            }
          }
        });

    _matchList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    _matchList.addListSelectionListener(
        new ListSelectionListener() {
          public void valueChanged(ListSelectionEvent e) {
            //        System.out.println("click!");
            removeListener();
            int i = _matchList.getSelectedIndex();
            if (i >= 0) {
              _pim.setCurrentItem(_pim.getMatchingItems().get(i));
              _matchList.ensureIndexIsVisible(i);
              updateInfo();
            }
            addListener();
          }
        });

    // put everything together
    Container contentPane = getContentPane();

    GridBagLayout layout = new GridBagLayout();
    contentPane.setLayout(layout);

    GridBagConstraints c = new GridBagConstraints();
    c.anchor = GridBagConstraints.NORTHWEST;
    c.weightx = 1.0;
    c.weighty = 0.0;
    c.gridwidth = GridBagConstraints.REMAINDER; // end row
    c.insets.top = 2;
    c.insets.left = 2;
    c.insets.bottom = 2;
    c.insets.right = 2;

    if (info) {
      c.fill = GridBagConstraints.NONE;
      contentPane.add(_infoLabel, c);
    }

    c.fill = GridBagConstraints.BOTH;
    c.weighty = 1.0;
    contentPane.add(
        new JScrollPane(
            _matchList,
            ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
            ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED),
        c);

    c.anchor = GridBagConstraints.SOUTHWEST;
    c.fill = GridBagConstraints.NONE;
    c.weightx = 0.0;
    c.weighty = 0.0;
    c.gridwidth = 1;
    contentPane.add(_tabCompletesLabel, c);

    c.fill = GridBagConstraints.HORIZONTAL;
    c.weightx = 1.0;
    c.gridwidth = GridBagConstraints.REMAINDER;
    contentPane.add(_sharedExtLabel, c);

    contentPane.add(_textField, c);

    _optionalComponents = makeOptions();
    if (_optionalComponents.length > 0) {
      _optionsPanel = new JPanel(new BorderLayout());
      _setupOptionsPanel(_optionalComponents);
      contentPane.add(_optionsPanel, c);
    }

    c.anchor = GridBagConstraints.SOUTHWEST;
    c.weightx = 1.0;
    c.weighty = 0.0;
    c.gridwidth = GridBagConstraints.REMAINDER; // end row
    c.insets.top = 2;
    c.insets.left = 2;
    c.insets.bottom = 2;
    c.insets.right = 2;

    JPanel buttonPanel = new JPanel(new GridBagLayout());
    GridBagConstraints bc = new GridBagConstraints();
    bc.insets.left = 2;
    bc.insets.right = 2;
    buttonPanel.add(new JLabel("Matching strategy:"), bc);
    buttonPanel.add(_strategyBox, bc);
    for (JButton b : _buttons) {
      buttonPanel.add(b, bc);
    }

    contentPane.add(buttonPanel, c);

    pack();
    //    Dimension parentDim = (_owner != null) ? _owner.getSize() : getToolkit().getScreenSize();
    //// int xs = (int) parentDim.getWidth()/3;
    //    int ys = (int) parentDim.getHeight()/4;
    //// in line below, parentDim was _owner.getSize(); changed because former could generate
    // NullPointerException
    //    setSize(new Dimension((int) getSize().getWidth(), (int)Math.min(parentDim.getHeight(),
    // Math.max(ys, 300))));
    if (_owner != null) {
      setLocationRelativeTo(_owner);
    }

    removeListener();
    updateTextField();
    addListener();
    updateList();
  }