Imported GNU Classpath 0.90
[official-gcc.git] / libjava / classpath / javax / swing / text / GlyphView.java
blobd505274c91f73a9faaa4897c419270d6bf8c9064
1 /* GlyphView.java -- A view to render styled text
2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing.text;
41 import java.awt.Color;
42 import java.awt.Font;
43 import java.awt.FontMetrics;
44 import java.awt.Graphics;
45 import java.awt.Rectangle;
46 import java.awt.Shape;
47 import java.awt.Toolkit;
48 import java.text.BreakIterator;
50 import javax.swing.SwingConstants;
51 import javax.swing.event.DocumentEvent;
52 import javax.swing.text.Position.Bias;
54 /**
55 * Renders a run of styled text. This {@link View} subclass paints the
56 * characters of the <code>Element</code> it is responsible for using
57 * the style information from that <code>Element</code>.
59 * @author Roman Kennke (roman@kennke.org)
61 public class GlyphView extends View implements TabableView, Cloneable
64 /**
65 * An abstract base implementation for a glyph painter for
66 * <code>GlyphView</code>.
68 public abstract static class GlyphPainter
70 /**
71 * Creates a new <code>GlyphPainer</code>.
73 public GlyphPainter()
75 // Nothing to do here.
78 /**
79 * Returns the ascent of the font that is used by this glyph painter.
81 * @param v the glyph view
83 * @return the ascent of the font that is used by this glyph painter
85 public abstract float getAscent(GlyphView v);
87 /**
88 * Returns the descent of the font that is used by this glyph painter.
90 * @param v the glyph view
92 * @return the descent of the font that is used by this glyph painter
94 public abstract float getDescent(GlyphView v);
96 /**
97 * Returns the full height of the rendered text.
99 * @return the full height of the rendered text
101 public abstract float getHeight(GlyphView view);
104 * Determines the model offset, so that the text between <code>p0</code>
105 * and this offset fits within the span starting at <code>x</code> with
106 * the length of <code>len</code>.
108 * @param v the glyph view
109 * @param p0 the starting offset in the model
110 * @param x the start location in the view
111 * @param len the length of the span in the view
113 public abstract int getBoundedPosition(GlyphView v, int p0, float x,
114 float len);
117 * Paints the glyphs.
119 * @param view the glyph view to paint
120 * @param g the graphics context to use for painting
121 * @param a the allocation of the glyph view
122 * @param p0 the start position (in the model) from which to paint
123 * @param p1 the end position (in the model) to which to paint
125 public abstract void paint(GlyphView view, Graphics g, Shape a, int p0,
126 int p1);
129 * Maps a position in the document into the coordinate space of the View.
130 * The output rectangle usually reflects the font height but has a width
131 * of zero.
133 * @param view the glyph view
134 * @param pos the position of the character in the model
135 * @param a the area that is occupied by the view
136 * @param b either {@link Position.Bias#Forward} or
137 * {@link Position.Bias#Backward} depending on the preferred
138 * direction bias. If <code>null</code> this defaults to
139 * <code>Position.Bias.Forward</code>
141 * @return a rectangle that gives the location of the document position
142 * inside the view coordinate space
144 * @throws BadLocationException if <code>pos</code> is invalid
145 * @throws IllegalArgumentException if b is not one of the above listed
146 * valid values
148 public abstract Shape modelToView(GlyphView view, int pos, Position.Bias b,
149 Shape a)
150 throws BadLocationException;
153 * Maps a visual position into a document location.
155 * @param v the glyph view
156 * @param x the X coordinate of the visual position
157 * @param y the Y coordinate of the visual position
158 * @param a the allocated region
159 * @param biasRet filled with the bias of the model location on method exit
161 * @return the model location that represents the specified view location
163 public abstract int viewToModel(GlyphView v, float x, float y, Shape a,
164 Position.Bias[] biasRet);
167 * Determine the span of the glyphs from location <code>p0</code> to
168 * location <code>p1</code>. If <code>te</code> is not <code>null</code>,
169 * then TABs are expanded using this <code>TabExpander</code>.
170 * The parameter <code>x</code> is the location at which the view is
171 * located (this is important when using TAB expansion).
173 * @param view the glyph view
174 * @param p0 the starting location in the document model
175 * @param p1 the end location in the document model
176 * @param te the tab expander to use
177 * @param x the location at which the view is located
179 * @return the span of the glyphs from location <code>p0</code> to
180 * location <code>p1</code>, possibly using TAB expansion
182 public abstract float getSpan(GlyphView view, int p0, int p1,
183 TabExpander te, float x);
187 * Returns the model location that should be used to place a caret when
188 * moving the caret through the document.
190 * @param v the glyph view
191 * @param pos the current model location
192 * @param b the bias for <code>p</code>
193 * @param a the allocated region for the glyph view
194 * @param direction the direction from the current position; Must be one of
195 * {@link SwingConstants#EAST}, {@link SwingConstants#WEST},
196 * {@link SwingConstants#NORTH} or {@link SwingConstants#SOUTH}
197 * @param biasRet filled with the bias of the resulting location when method
198 * returns
200 * @return the location within the document that should be used to place the
201 * caret when moving the caret around the document
203 * @throws BadLocationException if <code>pos</code> is an invalid model
204 * location
205 * @throws IllegalArgumentException if <code>d</code> is invalid
207 public int getNextVisualPositionFrom(GlyphView v, int pos, Position.Bias b,
208 Shape a, int direction,
209 Position.Bias[] biasRet)
210 throws BadLocationException
213 int result = pos;
214 switch (direction)
216 case SwingConstants.EAST:
217 result = pos + 1;
218 break;
219 case SwingConstants.WEST:
220 result = pos - 1;
221 break;
222 case SwingConstants.NORTH:
223 case SwingConstants.SOUTH:
224 default:
225 // This should be handled in enclosing view, since the glyph view
226 // does not layout vertically.
227 break;
229 return result;
233 * Returns a painter that can be used to render the specified glyph view.
234 * If this glyph painter is stateful, then it should return a new instance.
235 * However, if this painter is stateless it should return itself. The
236 * default behaviour is to return itself.
238 * @param v the glyph view for which to create a painter
239 * @param p0 the start offset of the rendered area
240 * @param p1 the end offset of the rendered area
242 * @return a painter that can be used to render the specified glyph view
244 public GlyphPainter getPainter(GlyphView v, int p0, int p1)
246 return this;
251 * The default <code>GlyphPainter</code> used in <code>GlyphView</code>.
253 static class DefaultGlyphPainter extends GlyphPainter
256 * Returns the full height of the rendered text.
258 * @return the full height of the rendered text
260 public float getHeight(GlyphView view)
262 Font font = view.getFont();
263 FontMetrics metrics = Toolkit.getDefaultToolkit().getFontMetrics(font);
264 float height = metrics.getHeight();
265 return height;
269 * Paints the glyphs.
271 * @param view the glyph view to paint
272 * @param g the graphics context to use for painting
273 * @param a the allocation of the glyph view
274 * @param p0 the start position (in the model) from which to paint
275 * @param p1 the end position (in the model) to which to paint
277 public void paint(GlyphView view, Graphics g, Shape a, int p0,
278 int p1)
280 Color oldColor = g.getColor();
281 int height = (int) getHeight(view);
282 Segment txt = view.getText(p0, p1);
283 Rectangle bounds = a.getBounds();
284 TabExpander tabEx = null;
285 View parent = view.getParent();
286 if (parent instanceof TabExpander)
287 tabEx = (TabExpander) parent;
289 int width = Utilities.getTabbedTextWidth(txt, g.getFontMetrics(),
290 bounds.x, tabEx, txt.offset);
291 // Fill the background of the text run.
292 Color background = view.getBackground();
293 if (background != null)
295 g.setColor(background);
296 g.fillRect(bounds.x, bounds.y, width, height);
298 // Draw the actual text.
299 g.setColor(view.getForeground());
300 g.setFont(view.getFont());
301 int ascent = g.getFontMetrics().getAscent();
302 if (view.isSuperscript())
303 // TODO: Adjust font for superscripting.
304 Utilities.drawTabbedText(txt, bounds.x, bounds.y + ascent - height / 2,
305 g, tabEx, txt.offset);
306 else if (view.isSubscript())
307 // TODO: Adjust font for subscripting.
308 Utilities.drawTabbedText(txt, bounds.x, bounds.y + ascent + height / 2,
309 g, tabEx, txt.offset);
310 else
311 Utilities.drawTabbedText(txt, bounds.x, bounds.y + ascent, g, tabEx,
312 txt.offset);
314 if (view.isStrikeThrough())
316 int strikeHeight = (int) (getAscent(view) / 2);
317 g.drawLine(bounds.x, bounds.y + strikeHeight, bounds.height + width,
318 bounds.y + strikeHeight);
320 if (view.isUnderline())
322 int lineHeight = (int) getAscent(view);
323 g.drawLine(bounds.x, bounds.y + lineHeight, bounds.height + width,
324 bounds.y + lineHeight);
326 g.setColor(oldColor);
330 * Maps a position in the document into the coordinate space of the View.
331 * The output rectangle usually reflects the font height but has a width
332 * of zero.
334 * @param view the glyph view
335 * @param pos the position of the character in the model
336 * @param a the area that is occupied by the view
337 * @param b either {@link Position.Bias#Forward} or
338 * {@link Position.Bias#Backward} depending on the preferred
339 * direction bias. If <code>null</code> this defaults to
340 * <code>Position.Bias.Forward</code>
342 * @return a rectangle that gives the location of the document position
343 * inside the view coordinate space
345 * @throws BadLocationException if <code>pos</code> is invalid
346 * @throws IllegalArgumentException if b is not one of the above listed
347 * valid values
349 public Shape modelToView(GlyphView view, int pos, Position.Bias b,
350 Shape a)
351 throws BadLocationException
353 Element el = view.getElement();
354 Font font = view.getFont();
355 FontMetrics fm = view.getContainer().getFontMetrics(font);
356 Segment txt = view.getText(el.getStartOffset(), pos);
357 int width = fm.charsWidth(txt.array, txt.offset, txt.count);
358 int height = fm.getHeight();
359 Rectangle bounds = a.getBounds();
360 Rectangle result = new Rectangle(bounds.x + width, bounds.y,
361 bounds.x + width, height);
362 return result;
366 * Determine the span of the glyphs from location <code>p0</code> to
367 * location <code>p1</code>. If <code>te</code> is not <code>null</code>,
368 * then TABs are expanded using this <code>TabExpander</code>.
369 * The parameter <code>x</code> is the location at which the view is
370 * located (this is important when using TAB expansion).
372 * @param view the glyph view
373 * @param p0 the starting location in the document model
374 * @param p1 the end location in the document model
375 * @param te the tab expander to use
376 * @param x the location at which the view is located
378 * @return the span of the glyphs from location <code>p0</code> to
379 * location <code>p1</code>, possibly using TAB expansion
381 public float getSpan(GlyphView view, int p0, int p1,
382 TabExpander te, float x)
384 Element el = view.getElement();
385 Font font = view.getFont();
386 FontMetrics fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
387 Segment txt = view.getText(p0, p1);
388 int span = Utilities.getTabbedTextWidth(txt, fm, (int) x, te, p0);
389 return span;
393 * Returns the ascent of the text run that is rendered by this
394 * <code>GlyphPainter</code>.
396 * @param v the glyph view
398 * @return the ascent of the text run that is rendered by this
399 * <code>GlyphPainter</code>
401 * @see FontMetrics#getAscent()
403 public float getAscent(GlyphView v)
405 Font font = v.getFont();
406 FontMetrics fm = v.getContainer().getFontMetrics(font);
407 return fm.getAscent();
411 * Returns the descent of the text run that is rendered by this
412 * <code>GlyphPainter</code>.
414 * @param v the glyph view
416 * @return the descent of the text run that is rendered by this
417 * <code>GlyphPainter</code>
419 * @see FontMetrics#getDescent()
421 public float getDescent(GlyphView v)
423 Font font = v.getFont();
424 FontMetrics fm = v.getContainer().getFontMetrics(font);
425 return fm.getDescent();
429 * Determines the model offset, so that the text between <code>p0</code>
430 * and this offset fits within the span starting at <code>x</code> with
431 * the length of <code>len</code>.
433 * @param v the glyph view
434 * @param p0 the starting offset in the model
435 * @param x the start location in the view
436 * @param len the length of the span in the view
438 public int getBoundedPosition(GlyphView v, int p0, float x, float len)
440 TabExpander te = v.getTabExpander();
441 Segment txt = v.getText(p0, v.getEndOffset());
442 Font font = v.getFont();
443 FontMetrics fm = v.getContainer().getFontMetrics(font);
444 int pos = Utilities.getTabbedTextOffset(txt, fm, (int) x,
445 (int) (x + len), te, p0, false);
446 return pos;
450 * Maps a visual position into a document location.
452 * @param v the glyph view
453 * @param x the X coordinate of the visual position
454 * @param y the Y coordinate of the visual position
455 * @param a the allocated region
456 * @param biasRet filled with the bias of the model location on method exit
458 * @return the model location that represents the specified view location
460 public int viewToModel(GlyphView v, float x, float y, Shape a,
461 Bias[] biasRet)
463 Rectangle b = a.getBounds();
464 int pos = getBoundedPosition(v, v.getStartOffset(), b.x, x - b.x);
465 return pos;
470 * The GlyphPainer used for painting the glyphs.
472 GlyphPainter glyphPainter;
475 * The start offset within the document for this view.
477 private int startOffset;
480 * The end offset within the document for this view.
482 private int endOffset;
485 * Creates a new <code>GlyphView</code> for the given <code>Element</code>.
487 * @param element the element that is rendered by this GlyphView
489 public GlyphView(Element element)
491 super(element);
492 startOffset = -1;
493 endOffset = -1;
497 * Returns the <code>GlyphPainter</code> that is used by this
498 * <code>GlyphView</code>. If no <code>GlyphPainer</code> has been installed
499 * <code>null</code> is returned.
501 * @return the glyph painter that is used by this
502 * glyph view or <code>null</code> if no glyph painter has been
503 * installed
505 public GlyphPainter getGlyphPainter()
507 return glyphPainter;
511 * Sets the {@link GlyphPainter} to be used for this <code>GlyphView</code>.
513 * @param painter the glyph painter to be used for this glyph view
515 public void setGlyphPainter(GlyphPainter painter)
517 glyphPainter = painter;
521 * Checks if a <code>GlyphPainer</code> is installed. If this is not the
522 * case, a default painter is installed.
524 protected void checkPainter()
526 if (glyphPainter == null)
527 glyphPainter = new DefaultGlyphPainter();
531 * Renders the <code>Element</code> that is associated with this
532 * <code>View</code>.
534 * @param g the <code>Graphics</code> context to render to
535 * @param a the allocated region for the <code>Element</code>
537 public void paint(Graphics g, Shape a)
539 Element el = getElement();
540 checkPainter();
541 getGlyphPainter().paint(this, g, a, getStartOffset(), getEndOffset());
546 * Returns the preferred span of the content managed by this
547 * <code>View</code> along the specified <code>axis</code>.
549 * @param axis the axis
551 * @return the preferred span of this <code>View</code>.
553 public float getPreferredSpan(int axis)
555 float span = 0;
556 checkPainter();
557 GlyphPainter painter = getGlyphPainter();
558 if (axis == X_AXIS)
560 Element el = getElement();
561 TabExpander tabEx = null;
562 View parent = getParent();
563 if (parent instanceof TabExpander)
564 tabEx = (TabExpander) parent;
565 span = painter.getSpan(this, getStartOffset(), getEndOffset(),
566 tabEx, 0.F);
568 else
569 span = painter.getHeight(this);
571 return span;
575 * Maps a position in the document into the coordinate space of the View.
576 * The output rectangle usually reflects the font height but has a width
577 * of zero.
579 * @param pos the position of the character in the model
580 * @param a the area that is occupied by the view
581 * @param b either {@link Position.Bias#Forward} or
582 * {@link Position.Bias#Backward} depending on the preferred
583 * direction bias. If <code>null</code> this defaults to
584 * <code>Position.Bias.Forward</code>
586 * @return a rectangle that gives the location of the document position
587 * inside the view coordinate space
589 * @throws BadLocationException if <code>pos</code> is invalid
590 * @throws IllegalArgumentException if b is not one of the above listed
591 * valid values
593 public Shape modelToView(int pos, Shape a, Position.Bias b)
594 throws BadLocationException
596 GlyphPainter p = getGlyphPainter();
597 return p.modelToView(this, pos, b, a);
601 * Maps coordinates from the <code>View</code>'s space into a position
602 * in the document model.
604 * @param x the x coordinate in the view space
605 * @param y the y coordinate in the view space
606 * @param a the allocation of this <code>View</code>
607 * @param b the bias to use
609 * @return the position in the document that corresponds to the screen
610 * coordinates <code>x, y</code>
612 public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
614 checkPainter();
615 GlyphPainter painter = getGlyphPainter();
616 return painter.viewToModel(this, x, y, a, b);
620 * Return the {@link TabExpander} to use.
622 * @return the {@link TabExpander} to use
624 public TabExpander getTabExpander()
626 TabExpander te = null;
627 View parent = getParent();
629 if (parent instanceof TabExpander)
630 te = (TabExpander) parent;
632 return te;
636 * Returns the preferred span of this view for tab expansion.
638 * @param x the location of the view
639 * @param te the tab expander to use
641 * @return the preferred span of this view for tab expansion
643 public float getTabbedSpan(float x, TabExpander te)
645 Element el = getElement();
646 return getGlyphPainter().getSpan(this, el.getStartOffset(),
647 el.getEndOffset(), te, x);
651 * Returns the span of a portion of the view. This is used in TAB expansion
652 * for fragments that don't contain TABs.
654 * @param p0 the start index
655 * @param p1 the end index
657 * @return the span of the specified portion of the view
659 public float getPartialSpan(int p0, int p1)
661 Element el = getElement();
662 Document doc = el.getDocument();
663 Segment seg = new Segment();
666 doc.getText(p0, p1 - p0, seg);
668 catch (BadLocationException ex)
670 AssertionError ae;
671 ae = new AssertionError("BadLocationException must not be thrown "
672 + "here");
673 ae.initCause(ex);
674 throw ae;
676 FontMetrics fm = null; // Fetch font metrics somewhere.
677 return Utilities.getTabbedTextWidth(seg, fm, 0, null, p0);
681 * Returns the start offset in the document model of the portion
682 * of text that this view is responsible for.
684 * @return the start offset in the document model of the portion
685 * of text that this view is responsible for
687 public int getStartOffset()
689 int start = startOffset;
690 if (start < 0)
691 start = super.getStartOffset();
692 return start;
696 * Returns the end offset in the document model of the portion
697 * of text that this view is responsible for.
699 * @return the end offset in the document model of the portion
700 * of text that this view is responsible for
702 public int getEndOffset()
704 int end = endOffset;
705 if (end < 0)
706 end = super.getEndOffset();
707 return end;
711 * Returns the text segment that this view is responsible for.
713 * @param p0 the start index in the document model
714 * @param p1 the end index in the document model
716 * @return the text segment that this view is responsible for
718 public Segment getText(int p0, int p1)
720 Segment txt = new Segment();
723 getDocument().getText(p0, p1 - p0, txt);
725 catch (BadLocationException ex)
727 AssertionError ae;
728 ae = new AssertionError("BadLocationException should not be "
729 + "thrown here. p0 = " + p0 + ", p1 = " + p1);
730 ae.initCause(ex);
731 throw ae;
734 return txt;
738 * Returns the font for the text run for which this <code>GlyphView</code>
739 * is responsible.
741 * @return the font for the text run for which this <code>GlyphView</code>
742 * is responsible
744 public Font getFont()
746 Element el = getElement();
747 AttributeSet atts = el.getAttributes();
748 String family = StyleConstants.getFontFamily(atts);
749 int size = StyleConstants.getFontSize(atts);
750 int style = Font.PLAIN;
751 if (StyleConstants.isBold(atts))
752 style |= Font.BOLD;
753 if (StyleConstants.isItalic(atts))
754 style |= Font.ITALIC;
755 Font font = new Font(family, style, size);
756 return font;
760 * Returns the foreground color which should be used to paint the text.
761 * This is fetched from the associated element's text attributes using
762 * {@link StyleConstants#getForeground}.
764 * @return the foreground color which should be used to paint the text
766 public Color getForeground()
768 Element el = getElement();
769 AttributeSet atts = el.getAttributes();
770 return StyleConstants.getForeground(atts);
774 * Returns the background color which should be used to paint the text.
775 * This is fetched from the associated element's text attributes using
776 * {@link StyleConstants#getBackground}.
778 * @return the background color which should be used to paint the text
780 public Color getBackground()
782 Element el = getElement();
783 AttributeSet atts = el.getAttributes();
784 // We cannot use StyleConstants.getBackground() here, because that returns
785 // BLACK as default (when background == null). What we need is the
786 // background setting of the text component instead, which is what we get
787 // when background == null anyway.
788 return (Color) atts.getAttribute(StyleConstants.Background);
792 * Determines whether the text should be rendered strike-through or not. This
793 * is determined using the method
794 * {@link StyleConstants#isStrikeThrough(AttributeSet)} on the element of
795 * this view.
797 * @return whether the text should be rendered strike-through or not
799 public boolean isStrikeThrough()
801 Element el = getElement();
802 AttributeSet atts = el.getAttributes();
803 return StyleConstants.isStrikeThrough(atts);
807 * Determines whether the text should be rendered as subscript or not. This
808 * is determined using the method
809 * {@link StyleConstants#isSubscript(AttributeSet)} on the element of
810 * this view.
812 * @return whether the text should be rendered as subscript or not
814 public boolean isSubscript()
816 Element el = getElement();
817 AttributeSet atts = el.getAttributes();
818 return StyleConstants.isSubscript(atts);
822 * Determines whether the text should be rendered as superscript or not. This
823 * is determined using the method
824 * {@link StyleConstants#isSuperscript(AttributeSet)} on the element of
825 * this view.
827 * @return whether the text should be rendered as superscript or not
829 public boolean isSuperscript()
831 Element el = getElement();
832 AttributeSet atts = el.getAttributes();
833 return StyleConstants.isSuperscript(atts);
837 * Determines whether the text should be rendered as underlined or not. This
838 * is determined using the method
839 * {@link StyleConstants#isUnderline(AttributeSet)} on the element of
840 * this view.
842 * @return whether the text should be rendered as underlined or not
844 public boolean isUnderline()
846 Element el = getElement();
847 AttributeSet atts = el.getAttributes();
848 return StyleConstants.isUnderline(atts);
852 * Creates and returns a shallow clone of this GlyphView. This is used by
853 * the {@link #createFragment} and {@link #breakView} methods.
855 * @return a shallow clone of this GlyphView
857 protected final Object clone()
861 return super.clone();
863 catch (CloneNotSupportedException ex)
865 AssertionError err = new AssertionError("CloneNotSupportedException "
866 + "must not be thrown here");
867 err.initCause(ex);
868 throw err;
873 * Tries to break the view near the specified view span <code>len</code>.
874 * The glyph view can only be broken in the X direction. For Y direction it
875 * returns itself.
877 * @param axis the axis for breaking, may be {@link View#X_AXIS} or
878 * {@link View#Y_AXIS}
879 * @param p0 the model location where the fragment should start
880 * @param pos the view position along the axis where the fragment starts
881 * @param len the desired length of the fragment view
883 * @return the fragment view, or <code>this</code> if breaking was not
884 * possible
886 public View breakView(int axis, int p0, float pos, float len)
888 if (axis == Y_AXIS)
889 return this;
891 checkPainter();
892 GlyphPainter painter = getGlyphPainter();
894 // Try to find a suitable line break.
895 BreakIterator lineBreaker = BreakIterator.getLineInstance();
896 Segment txt = new Segment();
899 int start = getStartOffset();
900 int length = getEndOffset() - start;
901 getDocument().getText(start, length, txt);
903 catch (BadLocationException ex)
905 AssertionError err = new AssertionError("BadLocationException must not "
906 + "be thrown here.");
907 err.initCause(ex);
908 throw err;
910 int breakLocation =
911 Utilities.getBreakLocation(txt, getContainer().getFontMetrics(getFont()),
912 (int) pos, (int) (pos + len),
913 getTabExpander(), p0);
914 View brokenView = createFragment(p0, breakLocation);
915 return brokenView;
919 * Determines how well the specified view location is suitable for inserting
920 * a line break. If <code>axis</code> is <code>View.Y_AXIS</code>, then
921 * this method forwards to the superclass, if <code>axis</code> is
922 * <code>View.X_AXIS</code> then this method returns
923 * {@link View#ExcellentBreakWeight} if there is a suitable break location
924 * (usually whitespace) within the specified view span, or
925 * {@link View#GoodBreakWeight} if not.
927 * @param axis the axis along which the break weight is requested
928 * @param pos the starting view location
929 * @param len the length of the span at which the view should be broken
931 * @return the break weight
933 public int getBreakWeight(int axis, float pos, float len)
935 int weight;
936 if (axis == Y_AXIS)
937 weight = super.getBreakWeight(axis, pos, len);
938 else
940 // FIXME: Commented out because the Utilities.getBreakLocation method
941 // is still buggy. The GoodBreakWeight is a reasonable workaround for
942 // now.
943 // int startOffset = getStartOffset();
944 // int endOffset = getEndOffset() - 1;
945 // Segment s = getText(startOffset, endOffset);
946 // Container c = getContainer();
947 // FontMetrics fm = c.getFontMetrics(c.getFont());
948 // int x0 = (int) pos;
949 // int x = (int) (pos + len);
950 // int breakLoc = Utilities.getBreakLocation(s, fm, x0, x,
951 // getTabExpander(),
952 // startOffset);
953 // if (breakLoc == startOffset || breakLoc == endOffset)
954 // weight = GoodBreakWeight;
955 // else
956 // weight = ExcellentBreakWeight;
957 weight = GoodBreakWeight;
959 return weight;
963 * Receives notification that some text attributes have changed within the
964 * text fragment that this view is responsible for. This calls
965 * {@link View#preferenceChanged(View, boolean, boolean)} on the parent for
966 * both width and height.
968 * @param e the document event describing the change; not used here
969 * @param a the view allocation on screen; not used here
970 * @param vf the view factory; not used here
972 public void changedUpdate(DocumentEvent e, Shape a, ViewFactory vf)
974 preferenceChanged(this, true, true);
978 * Receives notification that some text has been inserted within the
979 * text fragment that this view is responsible for. This calls
980 * {@link View#preferenceChanged(View, boolean, boolean)} for the
981 * direction in which the glyphs are rendered.
983 * @param e the document event describing the change; not used here
984 * @param a the view allocation on screen; not used here
985 * @param vf the view factory; not used here
987 public void insertUpdate(DocumentEvent e, Shape a, ViewFactory vf)
989 preferenceChanged(this, true, false);
993 * Receives notification that some text has been removed within the
994 * text fragment that this view is responsible for. This calls
995 * {@link View#preferenceChanged(View, boolean, boolean)} on the parent for
996 * width.
998 * @param e the document event describing the change; not used here
999 * @param a the view allocation on screen; not used here
1000 * @param vf the view factory; not used here
1002 public void removeUpdate(DocumentEvent e, Shape a, ViewFactory vf)
1004 preferenceChanged(this, true, false);
1008 * Creates a fragment view of this view that starts at <code>p0</code> and
1009 * ends at <code>p1</code>.
1011 * @param p0 the start location for the fragment view
1012 * @param p1 the end location for the fragment view
1014 * @return the fragment view
1016 public View createFragment(int p0, int p1)
1018 GlyphView fragment = (GlyphView) clone();
1019 if (p0 != getStartOffset())
1020 fragment.startOffset = p0;
1021 if (p1 != getEndOffset())
1022 fragment.endOffset = p1;
1023 return fragment;
1027 * Returns the alignment of this view along the specified axis. For the Y
1028 * axis this is <code>(height - descent) / height</code> for the used font,
1029 * so that it is aligned along the baseline.
1030 * For the X axis the superclass is called.
1032 public float getAlignment(int axis)
1034 float align;
1035 if (axis == Y_AXIS)
1037 checkPainter();
1038 GlyphPainter painter = getGlyphPainter();
1039 float height = painter.getHeight(this);
1040 float descent = painter.getDescent(this);
1041 align = (height - descent) / height;
1043 else
1044 align = super.getAlignment(axis);
1046 return align;
1050 * Returns the model location that should be used to place a caret when
1051 * moving the caret through the document.
1053 * @param pos the current model location
1054 * @param bias the bias for <code>p</code>
1055 * @param a the allocated region for the glyph view
1056 * @param direction the direction from the current position; Must be one of
1057 * {@link SwingConstants#EAST}, {@link SwingConstants#WEST},
1058 * {@link SwingConstants#NORTH} or {@link SwingConstants#SOUTH}
1059 * @param biasRet filled with the bias of the resulting location when method
1060 * returns
1062 * @return the location within the document that should be used to place the
1063 * caret when moving the caret around the document
1065 * @throws BadLocationException if <code>pos</code> is an invalid model
1066 * location
1067 * @throws IllegalArgumentException if <code>d</code> is invalid
1069 public int getNextVisualPositionFrom(int pos, Position.Bias bias, Shape a,
1070 int direction, Position.Bias[] biasRet)
1071 throws BadLocationException
1073 checkPainter();
1074 GlyphPainter painter = getGlyphPainter();
1075 return painter.getNextVisualPositionFrom(this, pos, bias, a, direction,
1076 biasRet);