Hi,

this fixes the blinking stuff in the DefaultCaret implementation as well
as some minor issues. Most importantly, this sets up the blink timer
when first needed, not earlier. Should save some threading/eventqueue
load when setting up a GUI with many text components. Also, this fixes
the conditions when the caret becomes visible by default (it should only
become visible when the focus is gained AND the text component is
editable and enabled). This fix makes the CornerCaret example from the
OReilly Swing book work just fine.

2005-11-02  Roman Kennke  <[EMAIL PROTECTED]>

        * javax/swing/text/DefaultCaret.java
        (BlinkTimerListener): New inner class. Listens for when the
        blink timer fires and updates the visible flag accordingly.      
  (visible): Default value for visible should be false.
        (blinkTimer): New field.
        (Caret): New constructor.
        (focusGained): Make the caret visible.
        (focusLost): Make caret invisible if the focus lost is permanent.
        (deinstall): Deinstall the blink timer.
        (repaint): Call getComponent() instead of directly accessing the
        textComponent field.
        (paint): Call getComponent() instead of directly accessing the
        textComponent field. Added an assert for the 'this should never
        happen' comment. Update the caret rectangle if damage hasn't
been
        called before.
        (setBlinkRate): Set the blink rate in the timer if there is
already
        a timer present.
        (setVisible): Call damage on the caret's location. Start/Stop
blink
        timer.
        (damage): New method. Updates the caret's bounds.
        * javax/swing/text/JTextComponent.java
        (CaretBlinkTimer): Removed unneeded inner class.
        (caretBlinkTimer): Removed unneeded field.
        (JTextComponent): Removed initialization of blink timer.
        (setEditable): Removed starting of blink timer.
        (setCaret): Likewise.
        * javax/swing/text/Utilities.java
        (getParagraphElement): New utility method.


/Roman
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 ([EMAIL PROTECTED])
+   */
+  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 <code>Caret</code> is currently visible or not.
+   * Indicates if this <code>Caret</code> 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 <code>DefaultCaret</code> 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 <a
    * href="http://java.sun.com/products/jfc/tsc/special_report/kestrel/keybindings.html";>this
    * report</a>, a pair of private classes wraps a [EMAIL PROTECTED]
@@ -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 <code>c</code> at
+   * the specified location <code>offset</code>.
+   *
+   * @param c the text component
+   * @param offset the offset of the paragraph element to return
+   *
+   * @return the paragraph element at <code>offset</code>
+   */
+  public static Element getParagraphElement(JTextComponent c, int offset)
+  {
+    Element root = c.getDocument().getDefaultRootElement();
+    int parIndex = root.getElementIndex(offset);
+    return root.getElement(parIndex);
+  }
 }
_______________________________________________
Classpath-patches mailing list
Classpath-patches@gnu.org
http://lists.gnu.org/mailman/listinfo/classpath-patches

Reply via email to