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 axis is View.Y_AXIS, then + * this method forwards to the superclass, if axis is + * View.X_AXIS then this method returns + * address@hidden View#ExcellentBreakWeight} if there is a suitable break location + * (usually whitespace) within the specified view span, or + * address@hidden 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 + * address@hidden 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 + * address@hidden 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 + * address@hidden 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 p0 and + * ends at p1. + * + * @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 [x0, x]. + * + * The parameter round controls which model location is returned + * if the view coordinates are on a character: If round is + * true, 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 round is false, 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 null, TABs are + * expanded to one space character + * @param p0 the starting model location + * @param round if true 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 [x0, x]. + * + * 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 null, 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); + } }