@Override
    public RelativePoint recalculateLocation(final Balloon object) {
      FindResult cursor = mySearchResults.getCursor();
      if (cursor == null) return null;
      final TextRange cur = cursor;
      int startOffset = cur.getStartOffset();
      int endOffset = cur.getEndOffset();

      if (startOffset >= myEditor.getDocument().getTextLength()) {
        if (!object.isDisposed()) {
          requestBalloonHiding(object);
        }
        return null;
      }
      if (!SearchResults.insideVisibleArea(myEditor, cur)) {
        requestBalloonHiding(object);

        VisibleAreaListener visibleAreaListener =
            new VisibleAreaListener() {
              @Override
              public void visibleAreaChanged(VisibleAreaEvent e) {
                if (SearchResults.insideVisibleArea(myEditor, cur)) {
                  showReplacementPreview();
                  final VisibleAreaListener visibleAreaListener = this;
                  final boolean remove = myVisibleAreaListenersToRemove.remove(visibleAreaListener);
                  if (remove) {
                    myEditor.getScrollingModel().removeVisibleAreaListener(visibleAreaListener);
                  }
                }
              }
            };
        myEditor.getScrollingModel().addVisibleAreaListener(visibleAreaListener);
        myVisibleAreaListenersToRemove.add(visibleAreaListener);
      }

      Point startPoint = myEditor.visualPositionToXY(myEditor.offsetToVisualPosition(startOffset));
      Point endPoint = myEditor.visualPositionToXY(myEditor.offsetToVisualPosition(endOffset));
      Point point = new Point((startPoint.x + endPoint.x) / 2, startPoint.y);

      return new RelativePoint(myEditor.getContentComponent(), point);
    }
 public ReplacementBalloonPositionTracker(Editor editor) {
   super(editor.getContentComponent());
   myEditor = editor;
 }