Index: javax/swing/text/DefaultCaret.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/text/DefaultCaret.java,v retrieving revision 1.19 diff -u -r1.19 DefaultCaret.java --- javax/swing/text/DefaultCaret.java 19 Oct 2005 14:57:30 -0000 1.19 +++ javax/swing/text/DefaultCaret.java 3 Nov 2005 11:18:11 -0000 @@ -40,6 +40,8 @@ import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.MouseEvent; @@ -50,6 +52,7 @@ import java.util.EventListener; import javax.swing.SwingUtilities; +import javax.swing.Timer; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; @@ -65,6 +68,27 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, MouseListener, MouseMotionListener { + + /** + * Controls the blinking of the caret. + * + * @author Roman Kennke (address@hidden) + */ + private class BlinkTimerListener implements ActionListener + { + /** + * Receives notification when the blink timer fires and updates the visible + * state of the caret. + * + * @param event the action event + */ + public void actionPerformed(ActionEvent event) + { + visible = !visible; + repaint(); + } + } + /** * Listens for changes in the text component's document and updates the * caret accordingly. @@ -238,15 +262,26 @@ private Point magicCaretPosition = null; /** - * Indicates if this Caret is currently visible or not. + * Indicates if this Caret is currently visible or not. This is + * package private to avoid an accessor method. */ - private boolean visible = true; + boolean visible = false; /** * The current highlight entry. */ private Object highlightEntry; + private Timer blinkTimer; + + /** + * Creates a new DefaultCaret instance. + */ + public DefaultCaret() + { + // Nothing to do here. + } + /** * Sets the Caret update policy. * @@ -381,7 +416,7 @@ */ public void focusGained(FocusEvent event) { - // TODO: Implement this properly. + setVisible(true); } /** @@ -391,7 +426,8 @@ */ public void focusLost(FocusEvent event) { - // TODO: Implement this properly. + if (event.isTemporary() == false) + setVisible(false); } /** @@ -433,6 +469,11 @@ textComponent.removePropertyChangeListener(propertyChangeListener); propertyChangeListener = null; textComponent = null; + + // Deinstall blink timer if present. + if (blinkTimer != null) + blinkTimer.stop(); + blinkTimer = null; } /** @@ -452,6 +493,7 @@ textComponent.addPropertyChangeListener(propertyChangeListener); documentListener = new DocumentHandler(); textComponent.getDocument().addDocumentListener(documentListener); + repaint(); } @@ -559,7 +601,7 @@ */ protected final void repaint() { - textComponent.repaint(this); + getComponent().repaint(x, y, width, height); } /** @@ -570,7 +612,8 @@ */ public void paint(Graphics g) { - if (textComponent == null) + JTextComponent comp = getComponent(); + if (comp == null) return; int dot = getDot(); @@ -578,25 +621,33 @@ try { - rect = textComponent.modelToView(dot); + rect = textComponent.modelToView(dot); } catch (BadLocationException e) { - // This should never happen as dot should be always valid. - return; + assert false : "Unexpected bad caret location: " + dot; + return; } if (rect == null) return; - - // First we need to delete the old caret. - // FIXME: Implement deleting of old caret. - + + // Check if paint has possibly been called directly, without a previous + // call to damage(). In this case we need to do some cleanup first. + if ((x != rect.x) || (y != rect.y)) + { + repaint(); // Erase previous location of caret. + x = rect.x; + y = rect.y; + width = 1; + height = rect.height; + } + // Now draw the caret on the new position if visible. if (visible) { - g.setColor(textComponent.getCaretColor()); - g.drawLine(rect.x, rect.y, rect.x, rect.y + rect.height); + g.setColor(textComponent.getCaretColor()); + g.drawLine(rect.x, rect.y, rect.x, rect.y + rect.height); } } @@ -687,6 +738,8 @@ */ public void setBlinkRate(int rate) { + if (blinkTimer != null) + blinkTimer.setDelay(rate); blinkRate = rate; } @@ -757,7 +810,29 @@ if (v != visible) { visible = v; - repaint(); + if (visible) + if (textComponent.isEnabled() && textComponent.isEditable()) + { + if (blinkTimer == null) + initBlinkTimer(); + blinkTimer.start(); + } + else + { + if (blinkTimer != null) + blinkTimer.stop(); + } + Rectangle area = null; + try + { + area = getComponent().modelToView(getDot()); + } + catch (BadLocationException ex) + { + assert false: "Unexpected bad caret location: " + getDot(); + } + if (area != null) + damage(area); } } @@ -771,5 +846,36 @@ protected Highlighter.HighlightPainter getSelectionPainter() { return DefaultHighlighter.DefaultPainter; + } + + /** + * Updates the carets rectangle properties to the specified rectangle and + * repaints the caret. + * + * @param r the rectangle to set as the caret rectangle + */ + protected void damage(Rectangle r) + { + if (r == null) + return; + x = r.x; + y = r.y; + width = 1; + // height is normally set in paint and we leave it untouched. However, we + // must set a valid value here, since otherwise the painting mechanism + // sets a zero clip and never calls paint. + if (height <= 0) + height = getComponent().getHeight(); + repaint(); + } + + /** + * Initializes the blink timer. + */ + private void initBlinkTimer() + { + // Setup the blink timer. + blinkTimer = new Timer(getBlinkRate(), new BlinkTimerListener()); + blinkTimer.setRepeats(true); } } Index: javax/swing/text/JTextComponent.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/text/JTextComponent.java,v retrieving revision 1.43 diff -u -r1.43 JTextComponent.java --- javax/swing/text/JTextComponent.java 19 Oct 2005 14:57:31 -0000 1.43 +++ javax/swing/text/JTextComponent.java 3 Nov 2005 11:18:11 -0000 @@ -50,7 +50,6 @@ import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.InputMethodListener; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; @@ -73,7 +72,6 @@ import javax.swing.KeyStroke; import javax.swing.Scrollable; import javax.swing.SwingConstants; -import javax.swing.Timer; import javax.swing.TransferHandler; import javax.swing.UIManager; import javax.swing.event.CaretEvent; @@ -304,48 +302,6 @@ } /** - * The timer that lets the caret blink. - */ - private class CaretBlinkTimer extends Timer implements ActionListener - { - /** - * Creates a new CaretBlinkTimer object with a default delay of 1 second. - */ - public CaretBlinkTimer() - { - super(1000, null); - addActionListener(this); - } - - /** - * Lets the caret blink. - */ - public void actionPerformed(ActionEvent ev) - { - Caret c = caret; - if (c != null) - c.setVisible(!c.isVisible()); - } - - /** - * Updates the blink delay according to the current caret. - */ - public void update() - { - stop(); - Caret c = caret; - if (c != null) - { - setDelay(c.getBlinkRate()); - if (editable) - start(); - else - c.setVisible(false); - } - } - } - - /** * According to this * report, a pair of private classes wraps a address@hidden @@ -701,8 +657,6 @@ private char focusAccelerator = '\0'; private NavigationFilter navigationFilter; - private CaretBlinkTimer caretBlinkTimer; - /** * Get a Keymap from the global keymap table, by name. * @@ -960,8 +914,6 @@ creatingKeymap = true; } - caretBlinkTimer = new CaretBlinkTimer(); - setFocusable(true); setEditable(true); enableEvents(AWTEvent.KEY_EVENT_MASK); @@ -1200,14 +1152,6 @@ if (editable == newValue) return; - if (newValue == true) - caretBlinkTimer.start(); - else - { - caretBlinkTimer.stop(); - caret.setVisible(false); - } - boolean oldValue = editable; editable = newValue; firePropertyChange("editable", oldValue, newValue); @@ -1235,8 +1179,6 @@ Caret oldCaret = caret; caret = newCaret; - - caretBlinkTimer.update(); if (caret != null) caret.install(this); Index: javax/swing/text/Utilities.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/text/Utilities.java,v retrieving revision 1.16 diff -u -r1.16 Utilities.java --- javax/swing/text/Utilities.java 31 Oct 2005 20:03:53 -0000 1.16 +++ javax/swing/text/Utilities.java 3 Nov 2005 11:18:11 -0000 @@ -522,4 +522,20 @@ // just break it on the character boundary return mark; } + + /** + * Returns the paragraph element in the text component c at + * the specified location offset. + * + * @param c the text component + * @param offset the offset of the paragraph element to return + * + * @return the paragraph element at offset + */ + public static Element getParagraphElement(JTextComponent c, int offset) + { + Element root = c.getDocument().getDefaultRootElement(); + int parIndex = root.getElementIndex(offset); + return root.getElement(parIndex); + } }