Hi all. I fixed to small errors in this patch that lead to strange behavior:
> + // Last line, from beginning-of-line to p1. > + r0.width = r1.x + r1.width; Had to add -1 to the calculation above otherwise there were drawing differences between single line and multi line selections. > + paintHighlight(g, r0); > } > + > + // Prevent useless write & repaint operations. > + if (o0 == o1 && o1 == p1) > + return; > + This expression wanted to be > + if (o0 == p0 && o1 == p1) Apart from that I updated the copyright headers in the affected files. After fixing that I cannot see any more problems with the highlighting mechanism. ChangeLog stays the same: 2006-02-21 Robert Schuster <[EMAIL PROTECTED]> * javax/swing/plaf/basic/BasicTextUI.java: (paint): Remove unneccessary part of the if-expression. (damageRange): Added case where the range spans multiple lines. * javax/swing/text/DefaultCaret.java: (clearHighlight): New method. (handleHighlight): Removed unneccessary part of the if-expression. (setDot): Use clearHighlight method. * javax/swing/text/DefaultHighlighter.java: Use ArrayList instead of Vector. (paint): Prevented calling size() on every loop iteration, fixed calculation of allocation area bounds. (getHighlights): Implemented. (removeHighlight): Mark damaged area in textcomponent. (addHighlight): Mark damaged area in textcomponent. (changeHighlight): Mark damaged area in textcomponent. (DefaultHighlighter.HighlightEntry): Made it a real Highlighter.Highlight implementation. (DefaultHighlighter.DefaultHighlightPainter.paint): Fixed calculations. cya Robert
Index: javax/swing/text/DefaultCaret.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/text/DefaultCaret.java,v retrieving revision 1.30 diff -u -r1.30 DefaultCaret.java --- javax/swing/text/DefaultCaret.java 9 Feb 2006 17:15:33 -0000 1.30 +++ javax/swing/text/DefaultCaret.java 21 Feb 2006 10:25:59 -0000 @@ -577,7 +577,39 @@ { return mark; } - + + private void clearHighlight() + { + Highlighter highlighter = textComponent.getHighlighter(); + + if (highlighter == null) + return; + + if (selectionVisible) + { + try + { + if (highlightEntry == null) + highlightEntry = highlighter.addHighlight(0, 0, getSelectionPainter()); + else + highlighter.changeHighlight(highlightEntry, 0, 0); + } + catch (BadLocationException e) + { + // This should never happen. + throw new InternalError(); + } + } + else + { + if (highlightEntry != null) + { + highlighter.removeHighlight(highlightEntry); + highlightEntry = null; + } + } + } + private void handleHighlight() { Highlighter highlighter = textComponent.getHighlighter(); @@ -588,7 +620,7 @@ int p0 = Math.min(dot, mark); int p1 = Math.max(dot, mark); - if (selectionVisible && p0 != p1) + if (selectionVisible) { try { @@ -818,6 +850,7 @@ if (doc != null) this.dot = Math.min(dot, doc.getLength()); this.dot = Math.max(this.dot, 0); + handleHighlight(); adjustVisibility(this); appear(); @@ -842,7 +875,8 @@ this.dot = Math.min(dot, doc.getLength()); this.dot = Math.max(this.dot, 0); this.mark = this.dot; - handleHighlight(); + + clearHighlight(); adjustVisibility(this); appear(); } Index: javax/swing/text/DefaultHighlighter.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/text/DefaultHighlighter.java,v retrieving revision 1.6 diff -u -r1.6 DefaultHighlighter.java --- javax/swing/text/DefaultHighlighter.java 19 Oct 2005 14:57:30 -0000 1.6 +++ javax/swing/text/DefaultHighlighter.java 21 Feb 2006 10:25:59 -0000 @@ -1,5 +1,5 @@ /* DefaultHighlighter.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -40,9 +40,10 @@ import java.awt.Color; import java.awt.Graphics; +import java.awt.Insets; import java.awt.Rectangle; import java.awt.Shape; -import java.util.Vector; +import java.util.ArrayList; public class DefaultHighlighter extends LayeredHighlighter { @@ -84,7 +85,7 @@ // This should never occur. return; } - + if (r0 == null || r1 == null) return; @@ -100,7 +101,7 @@ paintHighlight(g, r0); return; } - + // First line, from p0 to end-of-line. r0.width = rect.x + rect.width - r0.x; paintHighlight(g, r0); @@ -109,15 +110,19 @@ // have the same height -- not a good assumption with JEditorPane/JTextPane). r0.y += r0.height; r0.x = rect.x; - + r0.width = rect.width; + while (r0.y < r1.y) { paintHighlight(g, r0); r0.y += r0.height; } - // Last line, from beginnin-of-line to p1. - paintHighlight(g, r1); + // Last line, from beginning-of-line to p1. + // The "-1" is neccessary else we would paint one pixel column more + // than in the case where the selection is only on one line. + r0.width = r1.x + r1.width - 1; + paintHighlight(g, r0); } public Shape paintLayer(Graphics g, int p0, int p1, Shape bounds, @@ -127,7 +132,7 @@ } } - private class HighlightEntry + private class HighlightEntry implements Highlighter.Highlight { int p0; int p1; @@ -140,12 +145,12 @@ this.painter = painter; } - public int getStartPosition() + public int getStartOffset() { return p0; } - public int getEndPosition() + public int getEndOffset() { return p1; } @@ -163,7 +168,7 @@ new DefaultHighlightPainter(null); private JTextComponent textComponent; - private Vector highlights = new Vector(); + private ArrayList highlights = new ArrayList(); private boolean drawsLayeredHighlights = true; public DefaultHighlighter() @@ -208,12 +213,20 @@ checkPositions(p0, p1); HighlightEntry entry = new HighlightEntry(p0, p1, painter); highlights.add(entry); + + textComponent.getUI().damageRange(textComponent, p0, p1); + return entry; } public void removeHighlight(Object tag) { highlights.remove(tag); + + HighlightEntry entry = (HighlightEntry) tag; + textComponent.getUI().damageRange(textComponent, + entry.p0, + entry.p1); } public void removeAllHighlights() @@ -223,16 +236,30 @@ public Highlighter.Highlight[] getHighlights() { - return null; + return (Highlighter.Highlight[]) + highlights.toArray(new Highlighter.Highlight[highlights.size()]); } public void changeHighlight(Object tag, int p0, int p1) throws BadLocationException { + int o0, o1; + checkPositions(p0, p1); HighlightEntry entry = (HighlightEntry) tag; + o0 = entry.p0; + o1 = entry.p1; + + // Prevent useless write & repaint operations. + if (o0 == p0 && o1 == p1) + return; + entry.p0 = p0; entry.p1 = p1; + + textComponent.getUI().damageRange(textComponent, + Math.min(p0, o0), + Math.max(p1, o1)); } public void paintLayeredHighlights(Graphics g, int p0, int p1, @@ -244,13 +271,21 @@ public void paint(Graphics g) { + int size = highlights.size(); + // Check if there are any highlights. - if (highlights.size() == 0) + if (size == 0) return; + + // Prepares the rectangle of the inner drawing area. + Insets insets = textComponent.getInsets(); + Shape bounds = + new Rectangle(insets.left, + insets.top, + textComponent.getWidth() - insets.left - insets.right, + textComponent.getHeight() - insets.top - insets.bottom); - Shape bounds = textComponent.getBounds(); - - for (int index = 0; index < highlights.size(); ++index) + for (int index = 0; index < size; ++index) { HighlightEntry entry = (HighlightEntry) highlights.get(index); entry.painter.paint(g, entry.p0, entry.p1, bounds, textComponent); Index: javax/swing/plaf/basic/BasicTextUI.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicTextUI.java,v retrieving revision 1.69 diff -u -r1.69 BasicTextUI.java --- javax/swing/plaf/basic/BasicTextUI.java 20 Feb 2006 12:40:42 -0000 1.69 +++ javax/swing/plaf/basic/BasicTextUI.java 21 Feb 2006 10:25:59 -0000 @@ -1,5 +1,5 @@ /* BasicTextUI.java -- - Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -79,6 +79,7 @@ import javax.swing.text.JTextComponent; import javax.swing.text.Keymap; import javax.swing.text.Position; +import javax.swing.text.Utilities; import javax.swing.text.View; import javax.swing.text.ViewFactory; @@ -875,9 +876,19 @@ if (textComponent.isOpaque()) paintBackground(g); - if (highlighter != null - && textComponent.getSelectionStart() != textComponent.getSelectionEnd()) - highlighter.paint(g); + // Try painting with the highlighter without checking whether there + // is a selection because a highlighter can be used to do more than + // marking selected text. + if (highlighter != null) + { + // Handle restoring of the color here to prevent + // drawing problems when the Highlighter implementor + // forgets to restore it. + Color oldColor = g.getColor(); + highlighter.paint(g); + g.setColor(oldColor); + } + rootView.paint(g, getVisibleEditorRect()); @@ -945,9 +956,75 @@ { try { + // Limit p0 and p1 to sane values to prevent unfriendly + // BadLocationExceptions. This makes it possible for the highlighter + // to send us illegal values which can happen when a large number + // of selected characters are removed (eg. by pressing delete + // or backspace). + // The reference implementation does not throw an exception, too. + p0 = Math.min(p0, t.getDocument().getLength()); + p1 = Math.min(p1, t.getDocument().getLength()); + Rectangle l1 = modelToView(t, p0, firstBias); Rectangle l2 = modelToView(t, p1, secondBias); - t.repaint(l1.union(l2)); + if (l1.y == l2.y) + t.repaint(l1.union(l2)); + else + { + // The two rectangles lie on different lines and we need a + // different algorithm to calculate the damaged area: + // 1. The line of p0 is damaged from the position of p0 + // to the right border. + // 2. All lines between the ones where p0 and p1 lie on + // are completely damaged. Use the allocation area to find + // out the bounds. + // 3. The final line is damaged from the left bound to the + // position of p1. + Insets insets = t.getInsets(); + + // Damage first line until the end. + l1.width = insets.right + t.getWidth() - l1.x; + t.repaint(l1); + + // Note: Utilities.getPositionBelow() may return the offset + // that was put in. In that case there is no next line and + // we should stop searching for one. + + int posBelow = Utilities.getPositionBelow(t, p0, l1.x); + if (posBelow < p1 && posBelow != -1 && posBelow != p0) + { + // Take the rectangle of the offset we just found and grow it + // to the maximum width. Retain y because this is our start + // height. + Rectangle grow = modelToView(t, posBelow); + grow.x = insets.left; + grow.width = t.getWidth() + insets.right; + + // Find further lines which have to be damaged completely. + int nextPosBelow = posBelow; + while (nextPosBelow < p1 && nextPosBelow != -1 && posBelow != nextPosBelow) + { + posBelow = nextPosBelow; + nextPosBelow = Utilities.getPositionBelow(t, posBelow, l1.x); + } + // Now posBelow is an offset on the last line which has to be damaged + // completely. (newPosBelow is on the same line as p1) + + // Retrieve the rectangle of posBelow and use its y and height + // value to calculate the final height of the multiple line + // spanning rectangle. + Rectangle end = modelToView(t, posBelow); + grow.height = end.y + end.height - grow.y; + + // Mark that area as damage. + t.repaint(grow); + } + + // Damage last line from its beginning to the position of p1. + l2.width += l2.x; + l2.x = insets.left; + t.repaint(l2); + } } catch (BadLocationException ex) {
signature.asc
Description: OpenPGP digital signature