public static EditorFragmentComponent createEditorFragmentComponent(
      Editor editor, int startLine, int endLine, boolean showFolding, boolean showGutter) {
    final EditorEx editorEx = (EditorEx) editor;
    final Color old = editorEx.getBackgroundColor();
    Color backColor = getBackgroundColor(editor);
    editorEx.setBackgroundColor(backColor);
    EditorFragmentComponent fragmentComponent =
        new EditorFragmentComponent(editorEx, startLine, endLine, showFolding, showGutter);
    fragmentComponent.setBackground(backColor);

    editorEx.setBackgroundColor(old);
    return fragmentComponent;
  }
  public ImplementationViewComponent(PsiElement[] elements, final int index) {
    super(new BorderLayout());

    final Project project = elements.length > 0 ? elements[0].getProject() : null;
    EditorFactory factory = EditorFactory.getInstance();
    Document doc = factory.createDocument("");
    doc.setReadOnly(true);
    myEditor = factory.createEditor(doc, project);
    ((EditorEx) myEditor).setBackgroundColor(EditorFragmentComponent.getBackgroundColor(myEditor));

    final EditorSettings settings = myEditor.getSettings();
    settings.setAdditionalLinesCount(1);
    settings.setAdditionalColumnsCount(1);
    settings.setLineMarkerAreaShown(false);
    settings.setIndentGuidesShown(false);
    settings.setLineNumbersShown(false);
    settings.setFoldingOutlineShown(false);

    myBinarySwitch = new CardLayout();
    myViewingPanel = new JPanel(myBinarySwitch);
    myEditor.setBorder(null);
    ((EditorEx) myEditor).getScrollPane().setViewportBorder(JBScrollPane.createIndentBorder());
    myViewingPanel.add(myEditor.getComponent(), TEXT_PAGE_KEY);

    myBinaryPanel = new JPanel(new BorderLayout());
    myViewingPanel.add(myBinaryPanel, BINARY_PAGE_KEY);

    add(myViewingPanel, BorderLayout.CENTER);

    myToolbar = createToolbar();
    myLocationLabel = new JLabel();
    myCountLabel = new JLabel();

    final JPanel header = new JPanel(new BorderLayout(2, 0));
    header.setBorder(
        BorderFactory.createCompoundBorder(
            IdeBorderFactory.createBorder(SideBorder.BOTTOM),
            IdeBorderFactory.createEmptyBorder(0, 0, 0, 5)));
    final JPanel toolbarPanel = new JPanel(new GridBagLayout());
    final GridBagConstraints gc =
        new GridBagConstraints(
            GridBagConstraints.RELATIVE,
            0,
            1,
            1,
            0,
            0,
            GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(0, 2, 0, 0),
            0,
            0);
    toolbarPanel.add(myToolbar.getComponent(), gc);

    setPreferredSize(new Dimension(600, 400));

    update(
        elements,
        new PairFunction<PsiElement[], List<FileDescriptor>, Boolean>() {
          @Override
          public Boolean fun(
              final PsiElement[] psiElements, final List<FileDescriptor> fileDescriptors) {
            if (psiElements.length == 0) return false;
            myElements = psiElements;

            myIndex = index < myElements.length ? index : 0;
            PsiFile psiFile = getContainingFile(myElements[myIndex]);

            VirtualFile virtualFile = psiFile.getVirtualFile();
            EditorHighlighter highlighter;
            if (virtualFile != null)
              highlighter = HighlighterFactory.createHighlighter(project, virtualFile);
            else {
              String fileName = psiFile.getName(); // some artificial psi file, lets do best we can
              highlighter = HighlighterFactory.createHighlighter(project, fileName);
            }

            ((EditorEx) myEditor).setHighlighter(highlighter);

            gc.fill = GridBagConstraints.HORIZONTAL;
            gc.weightx = 1;
            if (myElements.length > 1) {
              myFileChooser =
                  new ComboBox(
                      fileDescriptors.toArray(new FileDescriptor[fileDescriptors.size()]), 250);
              updateRenderer(project);

              myFileChooser.addActionListener(
                  new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                      int index = myFileChooser.getSelectedIndex();
                      if (myIndex != index) {
                        myIndex = index;
                        updateControls();
                      }
                    }
                  });

              myLabel = new JLabel();
              myLabel.setVisible(false);
              toolbarPanel.add(myFileChooser, gc);
            } else {
              myFileChooser = new ComboBox();
              myFileChooser.setVisible(false);
              myCountLabel.setVisible(false);

              myLabel = new JLabel();
              VirtualFile file = psiFile.getVirtualFile();
              if (file != null) {
                myLabel.setIcon(getIconForFile(psiFile));
                myLabel.setForeground(
                    FileStatusManager.getInstance(project).getStatus(file).getColor());
                myLabel.setText(file.getPresentableName());
                myLabel.setBorder(
                    new CompoundBorder(
                        IdeBorderFactory.createRoundedBorder(),
                        IdeBorderFactory.createEmptyBorder(0, 0, 0, 5)));
              }
              toolbarPanel.add(myLabel, gc);
            }

            gc.fill = GridBagConstraints.NONE;
            gc.weightx = 0;
            toolbarPanel.add(myCountLabel, gc);

            header.add(toolbarPanel, BorderLayout.CENTER);
            header.add(myLocationLabel, BorderLayout.EAST);

            add(header, BorderLayout.NORTH);

            updateControls();
            return true;
          }
        });
  }
  /**
   * @param hideByAnyKey
   * @param x <code>x</code> coordinate in layered pane coordinate system.
   * @param y <code>y</code> coordinate in layered pane coordinate system.
   */
  @Nullable
  public static LightweightHint showEditorFragmentHintAt(
      Editor editor,
      TextRange range,
      int x,
      int y,
      boolean showUpward,
      boolean showFolding,
      boolean hideByAnyKey) {
    if (ApplicationManager.getApplication().isUnitTestMode()) return null;
    Document document = editor.getDocument();

    int startOffset = range.getStartOffset();
    int startLine = document.getLineNumber(startOffset);
    CharSequence text = document.getCharsSequence();
    // There is a possible case that we have a situation like below:
    //    line 1
    //    line 2 <fragment start>
    //    line 3<fragment end>
    // We don't want to include 'line 2' to the target fragment then.
    boolean incrementLine = false;
    for (int offset = startOffset, max = Math.min(range.getEndOffset(), text.length());
        offset < max;
        offset++) {
      char c = text.charAt(offset);
      incrementLine = StringUtil.isWhiteSpace(c);
      if (!incrementLine || c == '\n') {
        break;
      }
    }
    if (incrementLine) {
      startLine++;
    }

    int endLine =
        Math.min(document.getLineNumber(range.getEndOffset()) + 1, document.getLineCount() - 1);

    // if (editor.logicalPositionToXY(new LogicalPosition(startLine, 0)).y >=
    // editor.logicalPositionToXY(new LogicalPosition(endLine, 0)).y) return null;
    if (startLine >= endLine) return null;

    EditorFragmentComponent fragmentComponent =
        createEditorFragmentComponent(editor, startLine, endLine, showFolding, true);

    if (showUpward) {
      y -= fragmentComponent.getPreferredSize().height + 10;
      y = Math.max(0, y);
    }

    final JComponent c = editor.getComponent();
    x = SwingUtilities.convertPoint(c, new Point(-3, 0), UIUtil.getRootPane(c)).x; // IDEA-68016

    Point p = new Point(x, y);
    LightweightHint hint = new MyComponentHint(fragmentComponent);
    HintManagerImpl.getInstanceImpl()
        .showEditorHint(
            hint,
            editor,
            p,
            (hideByAnyKey ? HintManager.HIDE_BY_ANY_KEY : 0)
                | HintManager.HIDE_BY_TEXT_CHANGE
                | HintManager.HIDE_BY_MOUSEOVER,
            0,
            false,
            new HintHint(editor, p));
    return hint;
  }