/* * Determine the Y offset for the current row */ private int getOffsetY(int rowStartOffset, FontMetrics fontMetrics) throws BadLocationException { // Get the bounding rectangle of the row Rectangle r = component.modelToView(rowStartOffset); int lineHeight = fontMetrics.getHeight(); int y = r.y + r.height; int descent = 0; // The text needs to be positioned above the bottom of the bounding // rectangle based on the descent of the font(s) contained on the row. if (r.height == lineHeight) { // default font is being used descent = fontMetrics.getDescent(); } else { // We need to check all the attributes for font changes if (fonts == null) { fonts = new HashMap<String, FontMetrics>(); } Element root = component.getDocument().getDefaultRootElement(); int index = root.getElementIndex(rowStartOffset); Element line = root.getElement(index); for (int i = 0; i < line.getElementCount(); i++) { Element child = line.getElement(i); AttributeSet as = child.getAttributes(); String fontFamily = (String) as.getAttribute(StyleConstants.FontFamily); Integer fontSize = (Integer) as.getAttribute(StyleConstants.FontSize); String key = fontFamily + fontSize; FontMetrics fm = fonts.get(key); if (fm == null) { Font font = new Font(fontFamily, Font.PLAIN, fontSize); fm = component.getFontMetrics(font); fonts.put(key, fm); } descent = Math.max(descent, fm.getDescent()); } } return y - descent; }
/* * A document change may affect the number of displayed lines of text. * Therefore the lines numbers will also change. */ private void documentChanged() { // View of the component has not been updated at the time // the DocumentEvent is fired SwingUtilities.invokeLater( () -> { try { int endPos = component.getDocument().getLength(); Rectangle rect = component.modelToView(endPos); if (rect != null && rect.y != lastHeight) { setPreferredWidth(); repaint(); lastHeight = rect.y; } } catch (BadLocationException ex) { /* nothing to do */ } }); }
@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()); } }