Hi,

I hacked a little more on javax.swing.text. This patch makes it possible
to actually insert content into a styled text component using the
keyboard. Yay!

2005-09-14  Roman Kennke  <[EMAIL PROTECTED]>

        * javax/swing/text/DefaultStyledDocument.java
        (insertUpdate): Tweaked attribute comparison to avoid NPE.
        * javax/swing/text/GlyphView.java
        (DefaultGlyphPainter.getBoundedPosition): Implemented.
        (DefaultGlyphPainter.viewToModel): Implemented.
        (getTabExpander): Don't be specific to ParagraphView here. All
        parents that implement TabExpander can be accepted.
        (getBeginIndex): Removed. This method is not documented in the
        specs.
        (getBreakWeight): Implemented.
        (changedUpdate): Implemented.
        (insertUpdate): Implemented.
        (removeUpdate): Implemented.
        (createFragment): Implemented.
        (breakView): Use createFragment.
        * javax/swing/text/Utilities.java
        (getTabbedTextOffset): Implemented both variants of this method.


/Roman
Index: javax/swing/text/DefaultStyledDocument.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/DefaultStyledDocument.java,v
retrieving revision 1.9
diff -u -r1.9 DefaultStyledDocument.java
--- javax/swing/text/DefaultStyledDocument.java	13 Sep 2005 23:44:50 -0000	1.9
+++ javax/swing/text/DefaultStyledDocument.java	14 Sep 2005 21:21:09 -0000
@@ -1108,11 +1108,11 @@
         // joined with the previous element.
         if (specs.size() == 0)
           {
-            if (attr.isEqual(prev.getAttributes()))
+            if (prev.getAttributes().isEqual(attr))
               spec.setDirection(ElementSpec.JoinPreviousDirection);
           }
         // Check if we could probably be joined with the next element.
-        else if (attr.isEqual(next.getAttributes()))
+        else if (next.getAttributes().isEqual(attr))
           spec.setDirection(ElementSpec.JoinNextDirection);
 
         specs.add(spec);
Index: javax/swing/text/GlyphView.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/GlyphView.java,v
retrieving revision 1.6
diff -u -r1.6 GlyphView.java
--- javax/swing/text/GlyphView.java	13 Sep 2005 23:14:11 -0000	1.6
+++ javax/swing/text/GlyphView.java	14 Sep 2005 21:21:10 -0000
@@ -431,8 +431,13 @@
      */
     public int getBoundedPosition(GlyphView v, int p0, float x, float len)
     {
-      // TODO: Implement this properly.
-      throw new AssertionError("Not yet implemented.");
+      TabExpander te = v.getTabExpander();
+      Segment txt = v.getText(p0, v.getEndOffset());
+      Font font = v.getFont();
+      FontMetrics fm = v.getContainer().getFontMetrics(font);
+      int pos = Utilities.getTabbedTextOffset(txt, fm, (int) x,
+                                              (int) (x + len), te, p0, false);
+      return pos;
     }
 
     /**
@@ -446,10 +451,15 @@
      *
      * @return the model location that represents the specified view location
      */
-    public int viewToModel(GlyphView v, float x, float y, Shape a, Bias[] biasRet)
+    public int viewToModel(GlyphView v, float x, float y, Shape a,
+                           Bias[] biasRet)
     {
-      // TODO: Implement this properly.
-      throw new AssertionError("Not yet implemented.");
+      Rectangle b = a.getBounds();
+      assert b.contains(x, y) : "The coordinates are expected to be within the "
+                                + "view's bounds: x=" + x + ", y=" + y
+                                + "a=" + a;
+      int pos = getBoundedPosition(v, v.getStartOffset(), b.x, x - b.x);
+      return pos;
     }
   }
 
@@ -550,7 +560,6 @@
         View parent = getParent();
         if (parent instanceof TabExpander)
           tabEx = (TabExpander) parent;
-        // TODO: Figure out how to determine the x parameter.
         span = painter.getSpan(this, getStartOffset(), getEndOffset(),
                                tabEx, 0.F);
       }
@@ -611,12 +620,11 @@
    */
   public TabExpander getTabExpander()
   {
-    // TODO: Figure out if this is correct.
     TabExpander te = null;
     View parent = getParent();
 
-    if (parent instanceof ParagraphView)
-      te = (ParagraphView) parent;
+    if (parent instanceof TabExpander)
+      te = (TabExpander) parent;
     
     return te;
   }
@@ -664,18 +672,6 @@
   }
 
   /**
-   * Returns the starting offset in the document model of the portion
-   * of text that this view is responsible for.
-   *
-   * @return the starting offset in the document model of the portion
-   *         of text that this view is responsible for
-   */
-  public int getBeginIndex()
-  {
-    return getElement().getStartOffset();
-  }
-
-  /**
    * Returns the start offset in the document model of the portion
    * of text that this view is responsible for.
    *
@@ -895,40 +891,113 @@
     if (goodBreakLocation != BreakIterator.DONE)
       breakLocation = goodBreakLocation;
 
-    GlyphView brokenView = (GlyphView) clone();
-    brokenView.startOffset = p0;
-    brokenView.endOffset = breakLocation;
+    View brokenView = createFragment(p0, breakLocation);
     return brokenView;
   }
 
+  /**
+   * Determines how well the specified view location is suitable for inserting
+   * a line break. If <code>axis</code> is <code>View.Y_AXIS</code>, then
+   * this method forwards to the superclass, if <code>axis</code> is
+   * <code>View.X_AXIS</code> then this method returns
+   * [EMAIL PROTECTED] View#ExcellentBreakWeight} if there is a suitable break location
+   * (usually whitespace) within the specified view span, or
+   * [EMAIL PROTECTED] View#GoodBreakWeight} if not.
+   *
+   * @param axis the axis along which the break weight is requested
+   * @param pos the starting view location
+   * @param len the length of the span at which the view should be broken
+   *
+   * @return the break weight
+   */
   public int getBreakWeight(int axis, float pos, float len)
   {
-    // FIXME: Implement me.
-    throw new AssertionError("Not yet implemented.");
+    int weight;
+    if (axis == Y_AXIS)
+      weight = super.getBreakWeight(axis, pos, len);
+    else
+      {
+        // Determine the model locations at pos and pos + len.
+        int spanX = (int) getPreferredSpan(X_AXIS);
+        int spanY = (int) getPreferredSpan(Y_AXIS);
+        Rectangle dummyAlloc = new Rectangle(0, 0, spanX, spanY);
+        Position.Bias[] biasRet = new Position.Bias[1];
+        int offset1 = viewToModel(pos, spanY / 2, dummyAlloc, biasRet);
+        int offset2 = viewToModel(pos, spanY / 2, dummyAlloc, biasRet);
+        Segment txt = getText(offset1, offset2);
+        BreakIterator lineBreaker = BreakIterator.getLineInstance();
+        lineBreaker.setText(txt);
+        int breakLoc = lineBreaker.previous();
+        if (breakLoc == offset1)
+          weight = View.BadBreakWeight;
+        else if(breakLoc ==  BreakIterator.DONE)
+          weight = View.GoodBreakWeight;
+        else
+          weight = View.ExcellentBreakWeight;
+      }
+    return weight;
   }
 
+  /**
+   * Receives notification that some text attributes have changed within the
+   * text fragment that this view is responsible for. This calls
+   * [EMAIL PROTECTED] View#preferenceChanged(View, boolean, boolean)} on the parent for
+   * both width and height.
+   *
+   * @param e the document event describing the change; not used here
+   * @param a the view allocation on screen; not used here
+   * @param vf the view factory; not used here
+   */
   public void changedUpdate(DocumentEvent e, Shape a, ViewFactory vf)
   {
-    // FIXME: Implement me.
-    throw new AssertionError("Not yet implemented.");
+    getParent().preferenceChanged(this, true, true);
   }
 
+  /**
+   * Receives notification that some text has been inserted within the
+   * text fragment that this view is responsible for. This calls
+   * [EMAIL PROTECTED] View#preferenceChanged(View, boolean, boolean)} on the parent for
+   * width.
+   *
+   * @param e the document event describing the change; not used here
+   * @param a the view allocation on screen; not used here
+   * @param vf the view factory; not used here
+   */
   public void insertUpdate(DocumentEvent e, Shape a, ViewFactory vf)
   {
-    // FIXME: Implement me.
-    throw new AssertionError("Not yet implemented.");
+    getParent().preferenceChanged(this, true, false);
   }
 
+  /**
+   * Receives notification that some text has been removed within the
+   * text fragment that this view is responsible for. This calls
+   * [EMAIL PROTECTED] View#preferenceChanged(View, boolean, boolean)} on the parent for
+   * width.
+   *
+   * @param e the document event describing the change; not used here
+   * @param a the view allocation on screen; not used here
+   * @param vf the view factory; not used here
+   */
   public void removeUpdate(DocumentEvent e, Shape a, ViewFactory vf)
   {
-    // FIXME: Implement me.
-    throw new AssertionError("Not yet implemented.");
+    getParent().preferenceChanged(this, true, false);
   }
 
+  /**
+   * Creates a fragment view of this view that starts at <code>p0</code> and
+   * ends at <code>p1</code>.
+   *
+   * @param p0 the start location for the fragment view
+   * @param p1 the end location for the fragment view
+   *
+   * @return the fragment view
+   */
   public View createFragment(int p0, int p1)
   {
-    // FIXME: Implement me.
-    throw new AssertionError("Not yet implemented.");
+    GlyphView fragment = (GlyphView) clone();
+    fragment.startOffset = p0;
+    fragment.endOffset = p1;
+    return fragment;
   }
 
   /**
Index: javax/swing/text/Utilities.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/Utilities.java,v
retrieving revision 1.7
diff -u -r1.7 Utilities.java
--- javax/swing/text/Utilities.java	2 Jul 2005 20:32:51 -0000	1.7
+++ javax/swing/text/Utilities.java	14 Sep 2005 21:21:10 -0000
@@ -195,4 +195,89 @@
 
     return maxWidth;
   }
+
+  /**
+   * Provides a facility to map screen coordinates into a model location. For a
+   * given text fragment and start location within this fragment, this method
+   * determines the model location so that the resulting fragment fits best
+   * into the span <code>[x0, x]</code>.
+   *
+   * The parameter <code>round</code> controls which model location is returned
+   * if the view coordinates are on a character: If <code>round</code> is
+   * <code>true</code>, then the result is rounded up to the next character, so
+   * that the resulting fragment is the smallest fragment that is larger than
+   * the specified span. If <code>round</code> is <code>false</code>, then the
+   * resulting fragment is the largest fragment that is smaller than the
+   * specified span.
+   *
+   * @param s the text segment
+   * @param fm the font metrics to use
+   * @param x0 the starting screen location
+   * @param x the target screen location at which the requested fragment should
+   *        end
+   * @param te the tab expander to use; if this is <code>null</code>, TABs are
+   *        expanded to one space character
+   * @param p0 the starting model location
+   * @param round if <code>true</code> round up to the next location, otherwise
+   *        round down to the current location
+   *
+   * @return the model location, so that the resulting fragment fits within the
+   *         specified span
+   */
+  public static final int getTabbedTextOffset(Segment s, FontMetrics fm, int x0,
+                                              int x, TabExpander te, int p0,
+                                              boolean round)
+  {
+    // At the end of the for loop, this holds the requested model location
+    int pos;
+    int currentX = x0;
+    for (pos = p0; pos < s.getEndIndex(); pos++)
+      {
+        char nextChar = s.array[pos];
+        if (nextChar != '\n')
+          currentX += fm.charWidth(nextChar);
+        else
+          {
+            if (te == null)
+              currentX += fm.charWidth(' ');
+            else
+              currentX = (int) te.nextTabStop(currentX, pos);
+          }
+        if (currentX >= x)
+          {
+            if (! round)
+              pos--;
+            break;
+          }
+      }
+    return pos;
+  }
+
+  /**
+   * Provides a facility to map screen coordinates into a model location. For a
+   * given text fragment and start location within this fragment, this method
+   * determines the model location so that the resulting fragment fits best
+   * into the span <code>[x0, x]</code>.
+   *
+   * This method rounds up to the next location, so that the resulting fragment
+   * will be the smallest fragment of the text, that is greater than the
+   * specified span.
+   *
+   * @param s the text segment
+   * @param fm the font metrics to use
+   * @param x0 the starting screen location
+   * @param x the target screen location at which the requested fragment should
+   *        end
+   * @param te the tab expander to use; if this is <code>null</code>, TABs are
+   *        expanded to one space character
+   * @param p0 the starting model location
+   *
+   * @return the model location, so that the resulting fragment fits within the
+   *         specified span
+   */
+  public static final int getTabbedTextOffset(Segment s, FontMetrics fm, int x0,
+                                              int x, TabExpander te, int p0)
+  {
+    return getTabbedTextOffset(s, fm, x0, x, te, p0, true);
+  }
 }
_______________________________________________
Classpath-patches mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/classpath-patches

Reply via email to