public static @Nls String truncateStringWithEllipsis(final @Nls @NotNull String text, final int maxWidth, final WidthCalculator fm) {
    final int error = fm.stringWidth(ERROR_STR);
    final int wholeWidth = fm.stringWidth(text) + error;
    if (wholeWidth <= maxWidth || text.isEmpty()) return text;
    final int ellipsisWidth = fm.stringWidth(ELLIPSIS) + error; // plus some reserve
    if (ellipsisWidth >= maxWidth) return ELLIPSIS;

    final int availableWidth = maxWidth - ellipsisWidth;
    int currentLen = (int)Math.floor(availableWidth / (((double) wholeWidth) / text.length()));

    final String currentSubstring = text.substring(0, currentLen);
    int realWidth = fm.stringWidth(currentSubstring);

    int delta = 0;
    if (realWidth >= availableWidth) {
      for (int i = currentLen - 1; i >= 0; i--) {
        if ((realWidth - delta) < availableWidth) return text.substring(0, i) + ELLIPSIS;
        delta += fm.charWidth(currentSubstring.charAt(i));
      }
      return text.charAt(0) + ELLIPSIS;
    } else {
      for (int i = currentLen; i < text.length(); i++) {
        if ((realWidth + delta) >= availableWidth) return text.substring(0, i) + ELLIPSIS;
        delta += fm.charWidth(text.charAt(i));
      }
      return text.substring(0, currentLen) + ELLIPSIS;
    }
  }
public static @Nls String truncateStringWithEllipsis(final @Nls @NotNull String text, final int maxWidth, final WidthCalculator fm)