/** 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(); }