// ------------------------------
 public void
     scrollToCaret() { // not called - fixed with putting visible scrollbars on JScrollPane
   //
   Rectangle rect1 = scroller1.getViewport().getViewRect();
   double x1 = rect1.getX();
   double y1 = rect1.getY();
   double r1height = rect1.getHeight();
   double r1width = rect1.getWidth();
   Caret caret1 = editor1.getCaret();
   Point pt2 = caret1.getMagicCaretPosition(); // the end of the string
   double x2 = pt2.getX();
   double y2 = pt2.getY();
   if (((x2 > x1) && (x2 < (x1 + r1width))) && ((y2 > y1) && (y2 < (y1 + r1height)))) {
     // inview
   } else {
     double newheight = r1height / 2;
     double newwidth = r1width / 2;
     double x3 = pt2.getX() - newwidth;
     double y3 = pt2.getY() - newheight;
     if (x3 < 0) x3 = 0;
     if (y3 < 0) y3 = 0;
     Rectangle rect3 = new Rectangle((int) x3, (int) y3, (int) newwidth, (int) newheight);
     editor1.scrollRectToVisible(rect3);
   }
 } // end scrollToCaret
  static void updateStyle(JTextComponent comp, SynthContext context, String prefix) {
    SynthStyle style = context.getStyle();

    Color color = comp.getCaretColor();
    if (color == null || color instanceof UIResource) {
      comp.setCaretColor((Color) style.get(context, prefix + ".caretForeground"));
    }

    Color fg = comp.getForeground();
    if (fg == null || fg instanceof UIResource) {
      fg = style.getColorForState(context, ColorType.TEXT_FOREGROUND);
      if (fg != null) {
        comp.setForeground(fg);
      }
    }

    Object ar = style.get(context, prefix + ".caretAspectRatio");
    if (ar instanceof Number) {
      comp.putClientProperty("caretAspectRatio", ar);
    }

    context.setComponentState(SELECTED | FOCUSED);

    Color s = comp.getSelectionColor();
    if (s == null || s instanceof UIResource) {
      comp.setSelectionColor(style.getColor(context, ColorType.TEXT_BACKGROUND));
    }

    Color sfg = comp.getSelectedTextColor();
    if (sfg == null || sfg instanceof UIResource) {
      comp.setSelectedTextColor(style.getColor(context, ColorType.TEXT_FOREGROUND));
    }

    context.setComponentState(DISABLED);

    Color dfg = comp.getDisabledTextColor();
    if (dfg == null || dfg instanceof UIResource) {
      comp.setDisabledTextColor(style.getColor(context, ColorType.TEXT_FOREGROUND));
    }

    Insets margin = comp.getMargin();
    if (margin == null || margin instanceof UIResource) {
      margin = (Insets) style.get(context, prefix + ".margin");

      if (margin == null) {
        // Some places assume margins are non-null.
        margin = SynthLookAndFeel.EMPTY_UIRESOURCE_INSETS;
      }
      comp.setMargin(margin);
    }

    Caret caret = comp.getCaret();
    if (caret instanceof UIResource) {
      Object o = style.get(context, prefix + ".caretBlinkRate");
      if (o != null && o instanceof Integer) {
        Integer rate = (Integer) o;
        caret.setBlinkRate(rate.intValue());
      }
    }
  }
Beispiel #3
0
 /**
  * Replaces the currently selected content with new content represented by the given StyledText.
  * If there is no selection this amounts to an insert of the given text. If there is no
  * replacement text this amounts to a removal of the current selection. The replacement text will
  * have the attributes currently defined for input at the point of insertion. If the document is
  * not editable, beep and return
  *
  * @param content the content to replace the selection with
  * @see StyledText#insert
  */
 public static void replaceSelection(Word word, StyledText content) {
   Document doc = word.workspace.getDocument();
   String text;
   Caret caret = word.workspace.getCaret();
   int insertPos = 0;
   int i;
   int contentSize;
   if (doc != null) {
     try {
       int p0 = Math.min(caret.getDot(), caret.getMark());
       int p1 = Math.max(caret.getDot(), caret.getMark());
       // if there is any selection
       if (p0 != p1) {
         doc.remove(p0, p1 - p0);
       }
       // insert the content
       if (content != null) {
         content.insert(doc, p0);
       }
     } catch (BadLocationException ble) {
       javax.swing.UIManager.getLookAndFeel().provideErrorFeedback(word.workspace);
       return;
     }
   }
 }
Beispiel #4
0
  private void initializePane() {
    mode = INSERT;
    addKeyListener(
        new KeyAdapter() {

          public void keyPressed(KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_INSERT) {
              toggleTypingMode();
            }
          }
        });

    // all editors display another caret when in overwrite mode
    // replace it
    setFont(new Font("Monospaced", Font.PLAIN, 12));
    Caret c =
        new DefaultCaret() {

          public void paint(Graphics g) {
            if (mode == INSERT) {
              super.paint(g);
              return;
            }
            JTextComponent comp = getComponent();

            int dot = getDot();
            Rectangle r = null;
            char c;
            try {
              r = comp.modelToView(dot);
              if (r == null) return;
              c = comp.getText(dot, 1).charAt(0);
            } catch (BadLocationException e) {
              return;
            }

            // erase provious caret
            if ((x != r.x) || (y != r.y)) {
              repaint();
              x = r.x;
              y = r.y;
              height = r.height;
            }

            g.setColor(comp.getCaretColor());
            g.setXORMode(comp.getBackground());

            width = g.getFontMetrics().charWidth(c);
            if (c == '\t' || c == '\n') width = g.getFontMetrics().charWidth(' ');
            if (isVisible()) {
              g.fillRect(r.x, r.y, width, r.height);
            }
          }
        };
    c.setBlinkRate(500); // default rate
    setCaret(c);
  }
Beispiel #5
0
 // This is a workaround for a java bug causing the caret to jump to 0
 // on focus gain since the value is recalculated. bug #4740914 (rejected)
 protected void processFocusEvent(FocusEvent e) {
   if (e.getID() == FocusEvent.FOCUS_GAINED) {
     Caret c = getCaret();
     int cd = getCaret().getDot();
     int cm = getCaret().getMark();
     super.processFocusEvent(e);
     // Assumes this won't go out of bounds (e.g. text didn't change).
     // This is normally a safe assumption, since it seems like the value can't change.
     c.setDot(cm);
     c.moveDot(cd);
   } else super.processFocusEvent(e);
 }
Beispiel #6
0
  @Override
  public void internalFrameActivated(InternalFrameEvent e) {
    super.internalFrameActivated(e);

    mainFrame.pasteItem.setEnabled(canPaste());

    Caret caret = sourceArea.getCaret();
    doCaretUpdate(caret.getDot(), caret.getMark());

    setUndoItem();
    setRedoItem();
  }
Beispiel #7
0
  /**
   * Finds the next instance of the regular expression specified from the caret position. If a match
   * is found, it is replaced with the specified replacement string.
   *
   * @param textArea The text area in which to search.
   * @param toFind The regular expression to search for.
   * @param replaceWith The string to replace the found regex with.
   * @param forward Whether to search forward from the caret position or backward from it.
   * @param matchCase Whether the search should be case-sensitive.
   * @param wholeWord Whether there should be spaces or tabs on either side of the match.
   * @return Whether a match was found (and thus replaced).
   * @throws PatternSyntaxException If <code>toFind</code> is not a valid regular expression.
   * @throws IndexOutOfBoundsException If <code>replaceWith</code> references an invalid group (less
   *     than zero or greater than the number of groups matched).
   * @see #replace
   * @see #find
   */
  protected static boolean regexReplace(
      JTextArea textArea,
      String toFind,
      String replaceWith,
      boolean forward,
      boolean matchCase,
      boolean wholeWord)
      throws PatternSyntaxException {

    // Be smart about what position we're "starting" at. For example,
    // if they are searching backwards and there is a selection such that
    // the dot is past the mark, and the selection is the text for which
    // you're searching, this search will find and return the current
    // selection. So, in that case we start at the beginning of the
    // selection.
    Caret c = textArea.getCaret();
    int start = makeMarkAndDotEqual(textArea, forward);

    String findIn = getFindInText(textArea, start, forward);
    if (findIn == null) return false;

    // Find the next location of the text we're searching for.
    RegExReplaceInfo info =
        getRegExReplaceInfo(toFind, findIn, forward, matchCase, wholeWord, replaceWith);

    findIn = null; // May help garbage collecting.

    // If a match was found, do the replace and return!
    if (info != null) {

      // Without this, if JTextArea isn't in focus, selection won't
      // appear selected.
      c.setSelectionVisible(true);

      int matchStart = info.getStartIndex();
      int matchEnd = info.getEndIndex();
      if (forward) {
        matchStart += start;
        matchEnd += start;
      }
      selectAndPossiblyCenter(textArea, matchStart, matchEnd);
      textArea.replaceSelection(info.getReplacement());

      return true;
    }

    // No match.
    return false;
  }
  /**
   * Provides a way to determine the next visually represented model location at which one might
   * place a caret. Some views may not be visible, they might not be in the same order found in the
   * model, or they just might not allow access to some of the locations in the model.
   *
   * <p>NOTE: You should only call this method if the passed-in <code>javax.swing.text.View</code>
   * is an instance of {@link TokenOrientedView} and <code>javax.swing.text.TabExpander</code>;
   * otherwise, a <code>ClassCastException</code> could be thrown.
   *
   * @param pos the position to convert >= 0
   * @param a the allocated region in which to render
   * @param direction the direction from the current position that can be thought of as the arrow
   *     keys typically found on a keyboard. This will be one of the following values:
   *     <ul>
   *       <li>SwingConstants.WEST
   *       <li>SwingConstants.EAST
   *       <li>SwingConstants.NORTH
   *       <li>SwingConstants.SOUTH
   *     </ul>
   *
   * @return the location within the model that best represents the next location visual position
   * @exception BadLocationException
   * @exception IllegalArgumentException if <code>direction</code> doesn't have one of the legal
   *     values above
   */
  public static int getNextVisualPositionFrom(
      int pos, Position.Bias b, Shape a, int direction, Position.Bias[] biasRet, View view)
      throws BadLocationException {

    biasRet[0] = Position.Bias.Forward;

    // Do we want the "next position" above, below, to the left or right?
    switch (direction) {
      case NORTH:
      case SOUTH:
        if (pos == -1) {
          pos = (direction == NORTH) ? Math.max(0, view.getEndOffset() - 1) : view.getStartOffset();
          break;
        }
        RSyntaxTextArea target = (RSyntaxTextArea) view.getContainer();
        Caret c = (target != null) ? target.getCaret() : null;
        // YECK! Ideally, the x location from the magic caret
        // position would be passed in.
        Point mcp;
        if (c != null) mcp = c.getMagicCaretPosition();
        else mcp = null;
        int x;
        if (mcp == null) {
          Rectangle loc = target.modelToView(pos);
          x = (loc == null) ? 0 : loc.x;
        } else {
          x = mcp.x;
        }
        if (direction == NORTH) pos = getPositionAbove(target, pos, x, (TabExpander) view);
        else pos = getPositionBelow(target, pos, x, (TabExpander) view);
        break;

      case WEST:
        if (pos == -1) pos = Math.max(0, view.getEndOffset() - 1);
        else pos = Math.max(0, pos - 1);
        break;

      case EAST:
        if (pos == -1) pos = view.getStartOffset();
        else pos = Math.min(pos + 1, view.getDocument().getLength());
        break;

      default:
        throw new IllegalArgumentException("Bad direction: " + direction);
    }

    return pos;
  }
  /**
   * Perform the goto operation.
   *
   * @return whether the dialog should be made invisible or not
   */
  protected boolean performGoto() {
    JTextComponent c = EditorRegistry.lastFocusedComponent();
    if (c != null) {
      try {
        int line = Integer.parseInt(getGotoValueText());

        // issue 188976
        if (line == 0) line = 1;
        // end of issue 188976

        BaseDocument doc = Utilities.getDocument(c);
        if (doc != null) {
          int rowCount = Utilities.getRowCount(doc);
          if (line > rowCount) line = rowCount;

          // Obtain the offset where to jump
          int pos = Utilities.getRowStartFromLineOffset(doc, line - 1);

          BaseKit kit = Utilities.getKit(c);
          if (kit != null) {
            Action a = kit.getActionByName(ExtKit.gotoAction);
            if (a instanceof ExtKit.GotoAction) {
              pos = ((ExtKit.GotoAction) a).getOffsetFromLine(doc, line - 1);
            }
          }

          if (pos != -1) {
            Caret caret = c.getCaret();
            caret.setDot(pos);
          } else {
            c.getToolkit().beep();
            return false;
          }
        }
      } catch (NumberFormatException e) {
        c.getToolkit().beep();
        return false;
      }
    }
    return true;
  }
  /**
   * Finds the next instance of the string/regular expression specified from the caret position. If
   * a match is found, it is selected in this text area.
   *
   * @param textArea The text area in which to search.
   * @param context What to search for and all search options.
   * @return Whether a match was found (and thus selected).
   * @throws PatternSyntaxException If this is a regular expression search but the search text is an
   *     invalid regular expression.
   * @see #replace(RTextArea, SearchContext)
   * @see #replaceAll(RTextArea, SearchContext)
   */
  public static boolean find(JTextArea textArea, SearchContext context) {

    String text = context.getSearchFor();
    if (text == null || text.length() == 0) {
      return false;
    }

    // Be smart about what position we're "starting" at.  We don't want
    // to find a match in the currently selected text (if any), so we
    // start searching AFTER the selection if searching forward, and
    // BEFORE the selection if searching backward.
    Caret c = textArea.getCaret();
    boolean forward = context.getSearchForward();
    int start = forward ? Math.max(c.getDot(), c.getMark()) : Math.min(c.getDot(), c.getMark());

    String findIn = getFindInText(textArea, start, forward);
    if (findIn == null || findIn.length() == 0) return false;

    // Find the next location of the text we're searching for.
    if (!context.isRegularExpression()) {
      int pos =
          getNextMatchPos(text, findIn, forward, context.getMatchCase(), context.getWholeWord());
      findIn = null; // May help garbage collecting.
      if (pos != -1) {
        // Without this, if JTextArea isn't in focus, selection
        // won't appear selected.
        c.setSelectionVisible(true);
        pos = forward ? start + pos : pos;
        selectAndPossiblyCenter(textArea, pos, pos + text.length());
        return true;
      }
    } else {
      // Regex matches can have varying widths.  The returned point's
      // x- and y-values represent the start and end indices of the
      // match in findIn.
      Point regExPos =
          getNextMatchPosRegEx(
              text, findIn, forward, context.getMatchCase(), context.getWholeWord());
      findIn = null; // May help garbage collecting.
      if (regExPos != null) {
        // Without this, if JTextArea isn't in focus, selection
        // won't appear selected.
        c.setSelectionVisible(true);
        if (forward) {
          regExPos.translate(start, start);
        }
        selectAndPossiblyCenter(textArea, regExPos.x, regExPos.y);
        return true;
      }
    }

    // No match.
    return false;
  }
Beispiel #11
0
    public void actionPerformed(JTextComponent text) {
      indentationLogic = ((EditorPane) text).getIndentationLogic();
      StyledDocument doc = (StyledDocument) text.getDocument();
      Element map = doc.getDefaultRootElement();
      Caret c = text.getCaret();
      int dot = c.getDot();
      int mark = c.getMark();
      int line1 = map.getElementIndex(dot);

      if (dot != mark) {
        int line2 = map.getElementIndex(mark);
        int begin = Math.min(line1, line2);
        int end = Math.max(line1, line2);
        Element elem;
        try {
          for (line1 = begin; line1 < end; line1++) {
            elem = map.getElement(line1);
            handleDecreaseIndent(line1, elem, doc);
          }
          elem = map.getElement(end);
          int start = elem.getStartOffset();
          if (Math.max(c.getDot(), c.getMark()) != start) {
            handleDecreaseIndent(end, elem, doc);
          }
        } catch (BadLocationException ble) {
          Debug.error(me + "Problem while de-indenting line\n%s", ble.getMessage());
          UIManager.getLookAndFeel().provideErrorFeedback(text);
        }
      } else {
        Element elem = map.getElement(line1);
        try {
          handleDecreaseIndent(line1, elem, doc);
        } catch (BadLocationException ble) {
          Debug.error(me + "Problem while de-indenting line\n%s", ble.getMessage());
          UIManager.getLookAndFeel().provideErrorFeedback(text);
        }
      }
    }
Beispiel #12
0
    public void actionPerformed(JTextComponent text) {
      indentationLogic = ((EditorPane) text).getIndentationLogic();
      boolean indentError = false;
      Document doc = text.getDocument();
      Element map = doc.getDefaultRootElement();
      String tabWhitespace = PreferencesUser.getInstance().getTabWhitespace();
      Caret c = text.getCaret();
      int dot = c.getDot();
      int mark = c.getMark();
      int dotLine = map.getElementIndex(dot);
      int markLine = map.getElementIndex(mark);

      if (dotLine != markLine) {
        int first = Math.min(dotLine, markLine);
        int last = Math.max(dotLine, markLine);
        Element elem;
        int start;
        try {
          for (int i = first; i < last; i++) {
            elem = map.getElement(i);
            start = elem.getStartOffset();
            doc.insertString(start, tabWhitespace, null);
          }
          elem = map.getElement(last);
          start = elem.getStartOffset();
          if (Math.max(c.getDot(), c.getMark()) != start) {
            doc.insertString(start, tabWhitespace, null);
          }
        } catch (BadLocationException ble) {
          Debug.error(me + "Problem while indenting line\n%s", ble.getMessage());
          UIManager.getLookAndFeel().provideErrorFeedback(text);
        }
      } else {
        text.replaceSelection(tabWhitespace);
      }
    }
  /** Pair method to {@link #annotate}. It releases all resources. */
  private void release() {
    editorUI.removePropertyChangeListener(this);
    textComponent.removeComponentListener(this);
    doc.removeDocumentListener(this);
    caret.removeChangeListener(this);
    if (caretTimer != null) {
      caretTimer.removeActionListener(this);
    }
    elementAnnotations = Collections.<Element, AnnotateLine>emptyMap();
    previousRevisions = null;
    originalFiles = null;
    // cancel running annotation task if active
    if (latestAnnotationTask != null) {
      latestAnnotationTask.cancel();
    }
    AnnotationMarkProvider amp = AnnotationMarkInstaller.getMarkProvider(textComponent);
    if (amp != null) {
      amp.setMarks(Collections.<AnnotationMark>emptyList());
    }

    clearRecentFeedback();
  }
Beispiel #14
0
    @Override
    public void actionPerformed(ActionEvent e) {
      JTextComponent textArea = (JTextComponent) e.getSource();

      Caret caret = textArea.getCaret();
      int dot = caret.getDot();

      /*
       * Move to the beginning/end of selection on a "non-shifted"
       * left- or right-keypress.  We shouldn't have to worry about
       * navigation filters as, if one is being used, it let us get
       * to that position before.
       */
      if (!select) {
        switch (direction) {
          case SwingConstants.EAST:
            int mark = caret.getMark();
            if (dot != mark) {
              caret.setDot(Math.max(dot, mark));
              return;
            }
            break;
          case SwingConstants.WEST:
            mark = caret.getMark();
            if (dot != mark) {
              caret.setDot(Math.min(dot, mark));
              return;
            }
            break;
          default:
        }
      }

      Position.Bias[] bias = new Position.Bias[1];
      Point magicPosition = caret.getMagicCaretPosition();

      try {

        if (magicPosition == null
            && (direction == SwingConstants.NORTH || direction == SwingConstants.SOUTH)) {
          Rectangle r = textArea.modelToView(dot);
          magicPosition = new Point(r.x, r.y);
        }

        NavigationFilter filter = textArea.getNavigationFilter();

        if (filter != null) {
          dot =
              filter.getNextVisualPositionFrom(
                  textArea, dot, Position.Bias.Forward, direction, bias);
        } else {
          if (direction == SwingConstants.NORTH || direction == SwingConstants.SOUTH) {
            dot = getNSVisualPosition((EditorPane) textArea, dot, direction);
          } else {
            dot =
                textArea
                    .getUI()
                    .getNextVisualPositionFrom(
                        textArea, dot, Position.Bias.Forward, direction, bias);
          }
        }
        if (select) {
          caret.moveDot(dot);
        } else {
          caret.setDot(dot);
        }

        if (magicPosition != null
            && (direction == SwingConstants.NORTH || direction == SwingConstants.SOUTH)) {
          caret.setMagicCaretPosition(magicPosition);
        }

      } catch (BadLocationException ble) {
        Debug.error(me + "Problem while trying to move caret\n%s", ble.getMessage());
      }
    }
Beispiel #15
0
 public void setCaretPosition(int position) {
   Caret c = textView.getCaret();
   // move the caret
   c.setDot(position);
 }
Beispiel #16
0
 public int getCaretPosition() {
   Caret c = textView.getCaret();
   return c.getDot();
 }
 private void uninstallCarets(JTextComponent txtEditor2) {
   for (Caret c : carets) {
     c.deinstall(txtEditor2);
   }
   carets.clear();
 }
  // latestAnnotationTask business logic
  @Override
  public void run() {
    // get resource bundle
    ResourceBundle loc = NbBundle.getBundle(AnnotationBar.class);
    // give status bar "wait" indication // NOI18N
    StatusBar statusBar = editorUI.getStatusBar();
    recentStatusMessage = loc.getString("CTL_StatusBar_WaitFetchAnnotation"); // NOI18N
    statusBar.setText(StatusBar.CELL_MAIN, recentStatusMessage);

    // determine current line
    int line = -1;
    int offset = caret.getDot();
    try {
      line = Utilities.getLineOffset(doc, offset);
    } catch (BadLocationException ex) {
      Mercurial.LOG.log(Level.SEVERE, "Can not get line for caret at offset ", offset); // NOI18N
      clearRecentFeedback();
      return;
    }

    // handle locally modified lines
    AnnotateLine al = getAnnotateLine(line);
    if (al == null) {
      AnnotationMarkProvider amp = AnnotationMarkInstaller.getMarkProvider(textComponent);
      if (amp != null) {
        amp.setMarks(Collections.<AnnotationMark>emptyList());
      }
      clearRecentFeedback();
      if (recentRevision != null) {
        recentRevision = null;
        repaint();
      }
      return;
    }

    // handle unchanged lines
    String revision = al.getRevision();
    if (revision.equals(recentRevision) == false) {
      recentRevision = revision;
      repositoryRoot = Mercurial.getInstance().getRepositoryRoot(getCurrentFile());
      repaint();

      AnnotationMarkProvider amp = AnnotationMarkInstaller.getMarkProvider(textComponent);
      if (amp != null) {

        List<AnnotationMark> marks = new ArrayList<AnnotationMark>(elementAnnotations.size());
        // I cannot affort to lock elementAnnotations for long time
        // it's accessed from editor thread too
        Iterator<Map.Entry<Element, AnnotateLine>> it2;
        synchronized (elementAnnotations) {
          it2 =
              new HashSet<Map.Entry<Element, AnnotateLine>>(elementAnnotations.entrySet())
                  .iterator();
        }
        while (it2.hasNext()) {
          Map.Entry<Element, AnnotateLine> next = it2.next();
          AnnotateLine annotateLine = next.getValue();
          if (revision.equals(annotateLine.getRevision())) {
            Element element = next.getKey();
            if (elementAnnotations.containsKey(element) == false) {
              continue;
            }
            int elementOffset = element.getStartOffset();
            int lineNumber = NbDocument.findLineNumber((StyledDocument) doc, elementOffset);
            AnnotationMark mark = new AnnotationMark(lineNumber, revision);
            marks.add(mark);
          }

          if (Thread.interrupted()) {
            clearRecentFeedback();
            return;
          }
        }
        amp.setMarks(marks);
      }
    }

    if (al.getCommitMessage() != null) {
      recentStatusMessage = al.getCommitMessage();
      statusBar.setText(
          StatusBar.CELL_MAIN,
          al.getRevision()
              + ":"
              + al.getId()
              + " - "
              + al.getAuthor()
              + ": "
              + recentStatusMessage); // NOI18N
    } else {
      clearRecentFeedback();
    }
  }
  /** Result computed show it... Takes AnnotateLines and shows them. */
  public void annotationLines(File file, List<AnnotateLine> annotateLines) {
    // set repository root for popup menu, now should be the right time
    repositoryRoot = Mercurial.getInstance().getRepositoryRoot(getCurrentFile());
    final List<AnnotateLine> lines = new LinkedList<AnnotateLine>(annotateLines);
    int lineCount = lines.size();
    /** 0 based line numbers => 1 based line numbers */
    final int ann2editorPermutation[] = new int[lineCount];
    for (int i = 0; i < lineCount; i++) {
      ann2editorPermutation[i] = i + 1;
    }

    DiffProvider diff = (DiffProvider) Lookup.getDefault().lookup(DiffProvider.class);
    if (diff != null) {
      Reader r = new LinesReader(lines);
      Reader docReader = Utils.getDocumentReader(doc);
      try {

        Difference[] differences = diff.computeDiff(r, docReader);

        // customize annotation line numbers to match different reality
        // compule line permutation

        for (Difference d : differences) {
          int offset, editorStart;
          if (d.getType() == Difference.ADD) {
            offset = d.getSecondEnd() - d.getSecondStart() + 1;
            editorStart = d.getFirstStart();
          } else if (d.getType() == Difference.DELETE) {
            offset = d.getFirstEnd() - d.getFirstStart() + 1;
            editorStart = d.getFirstEnd();
            for (int c = editorStart - offset; c < editorStart; c++) {
              ann2editorPermutation[c] = -1;
            }
            offset = -offset;
          } else {
            // change
            int firstLen = d.getFirstEnd() - d.getFirstStart();
            int secondLen = d.getSecondEnd() - d.getSecondStart();
            offset = secondLen - firstLen;
            if (offset == 0) continue;
            editorStart = d.getFirstEnd();
            for (int c = d.getFirstStart(); c < editorStart; c++) {
              ann2editorPermutation[c] += -1;
            }
          }
          for (int c = editorStart; c < lineCount; c++) {
            ann2editorPermutation[c] += offset;
          }
        }

      } catch (IOException e) {
        Mercurial.LOG.log(
            Level.INFO,
            "Cannot compute local diff required for annotations, ignoring..."); // NOI18N
      }
    }

    doc.render(
        new Runnable() {
          @Override
          public void run() {
            StyledDocument sd = (StyledDocument) doc;
            Iterator<AnnotateLine> it = lines.iterator();
            previousRevisions = Collections.synchronizedMap(new HashMap<String, HgRevision>());
            originalFiles = Collections.synchronizedMap(new HashMap<String, File>());
            elementAnnotations =
                Collections.synchronizedMap(new HashMap<Element, AnnotateLine>(lines.size()));
            while (it.hasNext()) {
              AnnotateLine line = it.next();
              int lineNum = ann2editorPermutation[line.getLineNum() - 1];
              if (lineNum == -1) {
                continue;
              }
              try {
                int lineOffset = NbDocument.findLineOffset(sd, lineNum - 1);
                Element element = sd.getParagraphElement(lineOffset);
                elementAnnotations.put(element, line);
              } catch (IndexOutOfBoundsException ex) {
                // TODO how could I get line behind document end?
                // furtunately user does not spot it
                Mercurial.LOG.log(Level.INFO, null, ex);
              }
            }
          }
        });

    final String url = HgUtils.getRemoteRepository(repositoryRoot);
    final boolean isKenaiRepository = url != null && HgKenaiAccessor.getInstance().isKenai(url);
    if (isKenaiRepository) {
      kenaiUsersMap = new HashMap<String, KenaiUser>();
      Iterator<AnnotateLine> it = lines.iterator();
      while (it.hasNext()) {
        AnnotateLine line = it.next();
        String author = line.getAuthor();
        if (author != null && !author.equals("") && !kenaiUsersMap.keySet().contains(author)) {
          KenaiUser ku = HgKenaiAccessor.getInstance().forName(author, url);
          if (ku != null) {
            kenaiUsersMap.put(author, ku);
          }
        }
      }
    }

    // lazy listener registration
    caret.addChangeListener(this);
    this.caretTimer = new Timer(500, this);
    caretTimer.setRepeats(false);

    elementAnnotationsSubstitute = "";
    onCurrentLine();
    revalidate();
    repaint();
  }
 // ensures that the selection is visible
 // because textcomponent doesn't show selection
 // when they don't have focus
 public void focusGained(FocusEvent e) {
   Caret caret = ((JTextComponent) comp).getCaret();
   caret.setVisible(true);
   caret.setSelectionVisible(true);
 }
 @Override
 public void actionPerformed(ActionEvent e, JTextComponent target) {
   Caret caret = target.getCaret();
   int prev = getPreviousWordPosition(target.getDocument(), caret.getDot());
   caret.setDot(prev);
 }
 /**
  * Makes the caret's dot and mark the same location so that, for the next search in the specified
  * direction, a match will be found even if it was within the original dot and mark's selection.
  *
  * @param textArea The text area.
  * @param forward Whether the search will be forward through the document (<code>false</code>
  *     means backward).
  * @return The new dot and mark position.
  */
 private static int makeMarkAndDotEqual(JTextArea textArea, boolean forward) {
   Caret c = textArea.getCaret();
   int val = forward ? Math.min(c.getDot(), c.getMark()) : Math.max(c.getDot(), c.getMark());
   c.setDot(val);
   return val;
 }