public LookupCellRenderer(LookupImpl lookup) {
    EditorColorsScheme scheme = lookup.getEditor().getColorsScheme();
    myNormalFont = scheme.getFont(EditorFontType.PLAIN);
    myBoldFont = scheme.getFont(EditorFontType.BOLD);

    myLookup = lookup;
    myNameComponent = new MySimpleColoredComponent();
    myNameComponent.setIpad(new Insets(0, 0, 0, 0));

    myTailComponent = new MySimpleColoredComponent();
    myTailComponent.setIpad(new Insets(0, 0, 0, 0));

    myTypeLabel = new MySimpleColoredComponent();
    myTypeLabel.setIpad(new Insets(0, 0, 0, 0));

    myPanel = new LookupPanel();
    myPanel.add(myNameComponent, BorderLayout.WEST);
    myPanel.add(myTailComponent, BorderLayout.CENTER);
    myTailComponent.setBorder(new EmptyBorder(0, 0, 0, AFTER_TAIL));

    myPanel.add(myTypeLabel, BorderLayout.EAST);
    myTypeLabel.setBorder(new EmptyBorder(0, 0, 0, AFTER_TYPE));

    myNormalMetrics = myLookup.getEditor().getComponent().getFontMetrics(myNormalFont);
    myBoldMetrics = myLookup.getEditor().getComponent().getFontMetrics(myBoldFont);
  }
 /**
  * When the item is selected then we use default tree's selection foreground. It guaranties
  * readability of selected text in any LAF.
  */
 @Override
 public void append(
     @NotNull @Nls String fragment, @NotNull SimpleTextAttributes attributes, boolean isMainText) {
   if (mySelected && isFocused()) {
     super.append(
         fragment,
         new SimpleTextAttributes(attributes.getStyle(), UIUtil.getTreeSelectionForeground()),
         isMainText);
   } else if (mySelected && UIUtil.isUnderAquaBasedLookAndFeel()) {
     super.append(
         fragment,
         new SimpleTextAttributes(attributes.getStyle(), UIUtil.getTreeForeground()),
         isMainText);
   } else {
     super.append(fragment, attributes, isMainText);
   }
 }
  private int setTypeTextLabel(
      LookupElement item,
      final Color background,
      Color foreground,
      final LookupElementPresentation presentation,
      int allowedWidth,
      boolean selected,
      boolean nonFocusedSelection,
      FontMetrics normalMetrics) {
    final String givenText = presentation.getTypeText();
    final String labelText =
        trimLabelText(
            StringUtil.isEmpty(givenText) ? "" : " " + givenText, allowedWidth, normalMetrics);

    int used = RealLookupElementPresentation.getStringWidth(labelText, normalMetrics);

    final Icon icon = presentation.getTypeIcon();
    if (icon != null) {
      myTypeLabel.setIcon(icon);
      used += icon.getIconWidth();
    }

    Color sampleBackground = background;

    Object o = item.isValid() ? item.getObject() : null;
    //noinspection deprecation
    if (o instanceof LookupValueWithUIHint && StringUtil.isEmpty(labelText)) {
      //noinspection deprecation
      Color proposedBackground = ((LookupValueWithUIHint) o).getColorHint();
      if (proposedBackground != null) {
        sampleBackground = proposedBackground;
      }
      myTypeLabel.append("  ");
      used += normalMetrics.stringWidth("WW");
    } else {
      myTypeLabel.append(labelText);
    }

    myTypeLabel.setBackground(sampleBackground);
    myTypeLabel.setForeground(
        getTypeTextColor(item, foreground, presentation, selected, nonFocusedSelection));
    return used;
  }
  private int setItemTextLabel(
      LookupElement item,
      final Color foreground,
      final boolean selected,
      LookupElementPresentation presentation,
      int allowedWidth) {
    boolean bold = presentation.isItemTextBold();

    Font customItemFont = myLookup.getCustomFont(item, bold);
    myNameComponent.setFont(
        customItemFont != null ? customItemFont : bold ? myBoldFont : myNormalFont);
    int style = getStyle(bold, presentation.isStrikeout(), presentation.isItemTextUnderlined());

    final FontMetrics metrics = getRealFontMetrics(item, bold);
    final String name = trimLabelText(presentation.getItemText(), allowedWidth, metrics);
    int used = RealLookupElementPresentation.getStringWidth(name, metrics);

    renderItemName(item, foreground, selected, style, name, myNameComponent);
    return used;
  }
  private void renderItemName(
      LookupElement item,
      Color foreground,
      boolean selected,
      @SimpleTextAttributes.StyleAttributeConstant int style,
      String name,
      final SimpleColoredComponent nameComponent) {
    final SimpleTextAttributes base = new SimpleTextAttributes(style, foreground);

    final String prefix = item instanceof EmptyLookupItem ? "" : myLookup.itemPattern(item);
    if (prefix.length() > 0) {
      Iterable<TextRange> ranges = getMatchingFragments(prefix, name);
      if (ranges != null) {
        SimpleTextAttributes highlighted =
            new SimpleTextAttributes(
                style, selected ? SELECTED_PREFIX_FOREGROUND_COLOR : PREFIX_FOREGROUND_COLOR);
        SpeedSearchUtil.appendColoredFragments(nameComponent, name, ranges, base, highlighted);
        return;
      }
    }
    nameComponent.append(name, base);
  }
  private void setTailTextLabel(
      boolean isSelected,
      LookupElementPresentation presentation,
      Color foreground,
      int allowedWidth,
      boolean nonFocusedSelection,
      FontMetrics fontMetrics) {
    int style = getStyle(false, presentation.isStrikeout(), false);

    for (LookupElementPresentation.TextFragment fragment : presentation.getTailFragments()) {
      if (allowedWidth < 0) {
        return;
      }

      String trimmed = trimLabelText(fragment.text, allowedWidth, fontMetrics);
      myTailComponent.append(
          trimmed,
          new SimpleTextAttributes(
              style, getTailTextColor(isSelected, fragment, foreground, nonFocusedSelection)));
      allowedWidth -= RealLookupElementPresentation.getStringWidth(trimmed, fontMetrics);
    }
  }
 public int getIconIndent() {
   return myNameComponent.getIconTextGap() + myEmptyIcon.getIconWidth();
 }
  @Override
  public Component getListCellRendererComponent(
      final JList list, Object value, int index, boolean isSelected, boolean hasFocus) {

    boolean nonFocusedSelection =
        isSelected && myLookup.getFocusDegree() == LookupImpl.FocusDegree.SEMI_FOCUSED;
    if (!myLookup.isFocused()) {
      isSelected = false;
    }

    myIsSelected = isSelected;
    final LookupElement item = (LookupElement) value;
    final Color foreground = getForegroundColor(isSelected);
    final Color background =
        nonFocusedSelection
            ? SELECTED_NON_FOCUSED_BACKGROUND_COLOR
            : isSelected ? SELECTED_BACKGROUND_COLOR : BACKGROUND_COLOR;

    int allowedWidth = list.getWidth() - AFTER_TAIL - AFTER_TYPE - getIconIndent();

    FontMetrics normalMetrics = getRealFontMetrics(item, false);
    FontMetrics boldMetrics = getRealFontMetrics(item, true);
    final LookupElementPresentation presentation =
        new RealLookupElementPresentation(
            isSelected ? getMaxWidth() : allowedWidth, normalMetrics, boldMetrics, myLookup);
    AccessToken token = ReadAction.start();
    try {
      if (item.isValid()) {
        try {
          item.renderElement(presentation);
        } catch (Exception e) {
          LOG.error(e);
        } catch (Error e) {
          LOG.error(e);
        }
      } else {
        presentation.setItemTextForeground(JBColor.RED);
        presentation.setItemText("Invalid");
      }
    } finally {
      token.finish();
    }

    myNameComponent.clear();
    myNameComponent.setIcon(augmentIcon(presentation.getIcon(), myEmptyIcon));
    myNameComponent.setBackground(background);
    allowedWidth -=
        setItemTextLabel(
            item,
            new JBColor(
                isSelected ? SELECTED_FOREGROUND_COLOR : presentation.getItemTextForeground(),
                foreground),
            isSelected,
            presentation,
            allowedWidth);

    Font customFont = myLookup.getCustomFont(item, false);
    myTailComponent.setFont(customFont != null ? customFont : myNormalFont);
    myTypeLabel.setFont(customFont != null ? customFont : myNormalFont);

    myTypeLabel.clear();
    if (allowedWidth > 0) {
      allowedWidth -=
          setTypeTextLabel(
              item,
              background,
              foreground,
              presentation,
              isSelected ? getMaxWidth() : allowedWidth,
              isSelected,
              nonFocusedSelection,
              normalMetrics);
    }

    myTailComponent.clear();
    myTailComponent.setBackground(background);
    if (isSelected || allowedWidth >= 0) {
      setTailTextLabel(
          isSelected,
          presentation,
          foreground,
          isSelected ? getMaxWidth() : allowedWidth,
          nonFocusedSelection,
          normalMetrics);
    }

    if (mySelected.containsKey(index)) {
      if (!isSelected && mySelected.get(index)) {
        myPanel.setUpdateExtender(true);
      }
    }
    mySelected.put(index, isSelected);

    final double w =
        myNameComponent.getPreferredSize().getWidth()
            + myTailComponent.getPreferredSize().getWidth()
            + myTypeLabel.getPreferredSize().getWidth();

    boolean useBoxLayout =
        isSelected
            && w > list.getWidth()
            && ((JBList) list).getExpandableItemsHandler().isEnabled();
    if (useBoxLayout != myPanel.getLayout() instanceof BoxLayout) {
      myPanel.removeAll();
      if (useBoxLayout) {
        myPanel.setLayout(new BoxLayout(myPanel, BoxLayout.X_AXIS));
        myPanel.add(myNameComponent);
        myPanel.add(myTailComponent);
        myPanel.add(myTypeLabel);
      } else {
        myPanel.setLayout(new BorderLayout());
        myPanel.add(myNameComponent, BorderLayout.WEST);
        myPanel.add(myTailComponent, BorderLayout.CENTER);
        myPanel.add(myTypeLabel, BorderLayout.EAST);
      }
    }

    return myPanel;
  }
  @Override
  public final Component getTreeCellRendererComponent(
      JTree tree,
      Object value,
      boolean selected,
      boolean expanded,
      boolean leaf,
      int row,
      boolean hasFocus) {
    myTree = tree;

    clear();

    mySelected = selected;
    myFocusedCalculated = false;

    // We paint background if and only if tree path is selected and tree has focus.
    // If path is selected and tree is not focused then we just paint focused border.
    if (UIUtil.isFullRowSelectionLAF()) {
      setBackground(selected ? UIUtil.getTreeSelectionBackground() : null);
    } else if (WideSelectionTreeUI.isWideSelection(tree)) {
      setPaintFocusBorder(false);
      if (selected) {
        setBackground(
            hasFocus
                ? UIUtil.getTreeSelectionBackground()
                : UIUtil.getTreeUnfocusedSelectionBackground());
      }
    } else if (selected) {
      setPaintFocusBorder(true);
      if (isFocused()) {
        setBackground(UIUtil.getTreeSelectionBackground());
      } else {
        setBackground(null);
      }
    } else {
      setBackground(null);
    }

    if (value instanceof LoadingNode) {
      setForeground(JBColor.GRAY);
      setIcon(LOADING_NODE_ICON);
    } else {
      setForeground(tree.getForeground());
      setIcon(null);
    }

    if (UIUtil.isUnderGTKLookAndFeel()) {
      super.setOpaque(false); // avoid nasty background
      super.setIconOpaque(false);
    } else if (UIUtil.isUnderNimbusLookAndFeel() && selected && hasFocus) {
      super.setOpaque(false); // avoid erasing Nimbus focus frame
      super.setIconOpaque(false);
    } else if (WideSelectionTreeUI.isWideSelection(tree)) {
      super.setOpaque(false); // avoid erasing Nimbus focus frame
      super.setIconOpaque(false);
    } else {
      super.setOpaque(
          myOpaque
              || selected && hasFocus
              || selected && isFocused()); // draw selection background even for non-opaque tree
    }

    if (tree.getUI() instanceof WideSelectionTreeUI && UIUtil.isUnderAquaBasedLookAndFeel()) {
      setMyBorder(null);
      setIpad(new Insets(0, 2, 0, 2));
    }

    customizeCellRenderer(tree, value, selected, expanded, leaf, row, hasFocus);

    return this;
  }
 @Override
 public void setOpaque(boolean isOpaque) {
   myOpaque = isOpaque;
   super.setOpaque(isOpaque);
 }