/** Paints one view that corresponds to a line (or multiple lines if folding takes effect). */ private void paintView(View view, Graphics g, int yBase) { JTextComponent component = editorUI.getComponent(); if (component == null) return; BaseTextUI textUI = (BaseTextUI) component.getUI(); Element rootElem = textUI.getRootView(component).getElement(); int line = rootElem.getElementIndex(view.getStartOffset()); String annotation = ""; // NOI18N AnnotateLine al = null; if (!elementAnnotations.isEmpty()) { al = getAnnotateLine(line); if (al != null) { annotation = getDisplayName(al); // NOI18N } } else { annotation = elementAnnotationsSubstitute; } if (al != null && al.getRevision().equals(recentRevision)) { g.setColor(selectedColor()); } else { g.setColor(foregroundColor()); } int texty = yBase + editorUI.getLineAscent(); int textx = 2; g.drawString(annotation, textx, texty); }
/** 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 }
/** * Makes the bar visible and sensitive to LogOutoutListener events that should deliver actual * content to be displayed. */ public void annotate() { annotated = true; elementAnnotations = Collections.<Element, AnnotateLine>emptyMap(); doc.addDocumentListener(this); textComponent.addComponentListener(this); editorUI.addPropertyChangeListener(this); revalidate(); // resize the component }
/** GlyphGutter copy pasted utility method. */ private int getLineFromMouseEvent(MouseEvent e) { int line = -1; if (editorUI != null) { try { JTextComponent component = editorUI.getComponent(); BaseTextUI textUI = (BaseTextUI) component.getUI(); int clickOffset = textUI.viewToModel(component, new Point(0, e.getY())); line = Utilities.getLineOffset(doc, clickOffset); } catch (BadLocationException ble) { } } return line; }
/** * 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(); } }
protected @Override void installUI(JTextComponent c) { super.installUI(c); if (!attached) { attachSystemActionPerformer("incremental-search-forward"); attachSystemActionPerformer("replace"); attachSystemActionPerformer(ExtKit.gotoAction); attachSystemActionPerformer(ExtKit.showPopupMenuAction); // replacing DefaultEditorKit.deleteNextCharAction by BaseKit.removeSelectionAction // #41223 // attachSystemActionPerformer(BaseKit.removeSelectionAction); attached = true; } c.addFocusListener(focusL); }
/** 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(); }
/** * Clears the status bar if it contains the latest status message displayed by this annotation * bar. */ private void clearRecentFeedback() { StatusBar statusBar = editorUI.getStatusBar(); if (statusBar.getText(StatusBar.CELL_MAIN) == recentStatusMessage) { statusBar.setText(StatusBar.CELL_MAIN, ""); // NOI18N } }
// 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(); } }
protected @Override void uninstallUI(JTextComponent c) { super.uninstallUI(c); c.removeFocusListener(focusL); }