/* * We need to know if the caret is currently positioned on the line we * are about to paint so the line number can be highlighted. */ private boolean isCurrentLine(int rowStartOffset) { int caretPosition = component.getCaretPosition(); Element root = component.getDocument().getDefaultRootElement(); if (root.getElementIndex(rowStartOffset) == root.getElementIndex(caretPosition)) return true; else return false; }
// public static final String showElementTreeAction = "showElementTree"; // ------------------------------------------------------------- public void openFile(String currDirStr, String currFileStr) { if (fileDialog == null) { fileDialog = new FileDialog(this); } fileDialog.setMode(FileDialog.LOAD); if (!(currDirStr.equals(""))) { fileDialog.setDirectory(currDirStr); } if (!(currFileStr.equals(""))) { fileDialog.setFile(currFileStr); } fileDialog.show(); String file = fileDialog.getFile(); // cancel pushed if (file == null) { return; } String directory = fileDialog.getDirectory(); File f = new File(directory, file); if (f.exists()) { Document oldDoc = getEditor().getDocument(); if (oldDoc != null) // oldDoc.removeUndoableEditListener(undoHandler); /* if (elementTreePanel != null) { elementTreePanel.setEditor(null); } */ getEditor().setDocument(new PlainDocument()); fileDialog.setTitle(file); Thread loader = new FileLoader(f, editor1.getDocument()); loader.start(); } }
/* * Get the line number to be drawn. The empty string will be returned * when a line of text has wrapped. */ protected String getTextLineNumber(int rowStartOffset) { Element root = component.getDocument().getDefaultRootElement(); int index = root.getElementIndex(rowStartOffset); Element line = root.getElement(index); if (line.getStartOffset() == rowStartOffset) return String.valueOf(index + 1); else return ""; }
/** * Create a line number component for a text component. * * @param argComponent the related text component * @param argMinimumDisplayDigits the number of digits used to calculate the minimum width of the * component. */ public TextLineNumber(JTextComponent argComponent, int argMinimumDisplayDigits) { component = argComponent; setFont(argComponent.getFont()); setBorderGap(5); setCurrentLineForeground(Color.RED); setDigitAlignment(RIGHT); setMinimumDisplayDigits(argMinimumDisplayDigits); argComponent.getDocument().addDocumentListener(this); argComponent.addCaretListener(this); argComponent.addPropertyChangeListener("font", this); }
// // Implement CaretListener interface // @Override public void caretUpdate(CaretEvent e) { // Get the line the caret is positioned on int caretPosition = component.getCaretPosition(); Element root = component.getDocument().getDefaultRootElement(); int currentLine = root.getElementIndex(caretPosition); // Need to repaint so the correct line number can be highlighted if (lastLine != currentLine) { repaint(); lastLine = currentLine; } }
/* * 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; }
/** Calculate the width needed to display the maximum line number */ private void setPreferredWidth() { Element root = component.getDocument().getDefaultRootElement(); int lines = root.getElementCount(); int digits = Math.max(String.valueOf(lines).length(), minimumDisplayDigits); // Update sizes when number of digits in the line number changes if (lastDigits != digits) { lastDigits = digits; FontMetrics fontMetrics = getFontMetrics(getFont()); int width = fontMetrics.charWidth('0') * digits; Insets insets = getInsets(); int preferredWidth = insets.left + insets.right + width; Dimension d = getPreferredSize(); d.setSize(preferredWidth, HEIGHT); setPreferredSize(d); setSize(d); } }
/* * 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 */ } }); }