protected void waitForFolding(JTextComponent target, int maxMiliSeconds) {
    // wait for parser and folding hierarchy creation
    int time = (int) maxMiliSeconds / 100;

    AbstractDocument adoc = (AbstractDocument) target.getDocument();

    // Dump fold hierarchy
    FoldHierarchy hierarchy = FoldHierarchy.get(target);
    int foldCount = 0;
    while (foldCount == 0 && time > 0) {

      adoc.readLock();
      try {
        hierarchy.lock();
        try {
          foldCount = hierarchy.getRootFold().getFoldCount();
        } finally {
          hierarchy.unlock();
        }
      } finally {
        adoc.readUnlock();
      }

      try {
        Thread.currentThread().sleep(100);
      } catch (InterruptedException ex) {
        time = 0;
      }
      time--;
    }
  }
  /**
   * GlyphGutter copy pasted bolerplate method. It invokes {@link #paintView} that contains actual
   * business logic.
   */
  @Override
  public void paintComponent(Graphics g) {
    super.paintComponent(g);

    Rectangle clip = g.getClipBounds();

    JTextComponent component = editorUI.getComponent();
    if (component == null) return;

    BaseTextUI textUI = (BaseTextUI) component.getUI();
    View rootView = Utilities.getDocumentView(component);
    if (rootView == null) return;

    g.setColor(backgroundColor());
    g.fillRect(clip.x, clip.y, clip.width, clip.height);

    AbstractDocument doc = (AbstractDocument) component.getDocument();
    doc.readLock();
    try {
      foldHierarchy.lock();
      try {
        int startPos = textUI.getPosFromY(clip.y);
        int startViewIndex = rootView.getViewIndex(startPos, Position.Bias.Forward);
        int rootViewCount = rootView.getViewCount();

        if (startViewIndex >= 0 && startViewIndex < rootViewCount) {
          int clipEndY = clip.y + clip.height;
          for (int i = startViewIndex; i < rootViewCount; i++) {
            View view = rootView.getView(i);
            Rectangle rec = component.modelToView(view.getStartOffset());
            if (rec == null) {
              break;
            }
            int y = rec.y;
            paintView(view, g, y);
            if (y >= clipEndY) {
              break;
            }
          }
        }

      } finally {
        foldHierarchy.unlock();
      }
    } catch (BadLocationException ble) {
      Mercurial.LOG.log(Level.WARNING, null, ble);
    } finally {
      doc.readUnlock();
    }
  }
 /** Creates new instance initializing final fields. */
 public AnnotationBar(JTextComponent target) {
   this.textComponent = target;
   this.editorUI = Utilities.getEditorUI(target);
   this.foldHierarchy = FoldHierarchy.get(editorUI.getComponent());
   this.doc = editorUI.getDocument();
   this.caret = textComponent.getCaret();
   setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
   elementAnnotationsSubstitute = ""; // NOI18N
 }
  public static String foldHierarchyToString(JTextComponent target) {
    String ret = "";
    AbstractDocument adoc = (AbstractDocument) target.getDocument();

    // Dump fold hierarchy
    FoldHierarchy hierarchy = FoldHierarchy.get(target);
    adoc.readLock();
    try {
      hierarchy.lock();
      try {
        Fold root = hierarchy.getRootFold();
        ret = (root == null) ? "root is null" : foldToStringChildren(root, 0); // NOI18N
      } finally {
        hierarchy.unlock();
      }
    } finally {
      adoc.readUnlock();
    }
    return ret;
  }