GNU Classpath (0.19) | ||
Frames | No Frames |
1: /* GlyphView.java -- A view to render styled text 2: Copyright (C) 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 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. 10: 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. 15: 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. 20: 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. 25: 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. */ 37: 38: 39: package javax.swing.text; 40: 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; 49: 50: import javax.swing.SwingConstants; 51: import javax.swing.event.DocumentEvent; 52: import javax.swing.text.Position.Bias; 53: 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>. 58: * 59: * @author Roman Kennke (roman@kennke.org) 60: */ 61: public class GlyphView extends View implements TabableView, Cloneable 62: { 63: 64: /** 65: * An abstract base implementation for a glyph painter for 66: * <code>GlyphView</code>. 67: */ 68: public abstract static class GlyphPainter 69: { 70: /** 71: * Creates a new <code>GlyphPainer</code>. 72: */ 73: public GlyphPainter() 74: { 75: // Nothing to do here. 76: } 77: 78: /** 79: * Returns the ascent of the font that is used by this glyph painter. 80: * 81: * @param v the glyph view 82: * 83: * @return the ascent of the font that is used by this glyph painter 84: */ 85: public abstract float getAscent(GlyphView v); 86: 87: /** 88: * Returns the descent of the font that is used by this glyph painter. 89: * 90: * @param v the glyph view 91: * 92: * @return the descent of the font that is used by this glyph painter 93: */ 94: public abstract float getDescent(GlyphView v); 95: 96: /** 97: * Returns the full height of the rendered text. 98: * 99: * @return the full height of the rendered text 100: */ 101: public abstract float getHeight(GlyphView view); 102: 103: /** 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>. 107: * 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 112: */ 113: public abstract int getBoundedPosition(GlyphView v, int p0, float x, 114: float len); 115: 116: /** 117: * Paints the glyphs. 118: * 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 124: */ 125: public abstract void paint(GlyphView view, Graphics g, Shape a, int p0, 126: int p1); 127: 128: /** 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. 132: * 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> 140: * 141: * @return a rectangle that gives the location of the document position 142: * inside the view coordinate space 143: * 144: * @throws BadLocationException if <code>pos</code> is invalid 145: * @throws IllegalArgumentException if b is not one of the above listed 146: * valid values 147: */ 148: public abstract Shape modelToView(GlyphView view, int pos, Position.Bias b, 149: Shape a) 150: throws BadLocationException; 151: 152: /** 153: * Maps a visual position into a document location. 154: * 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 160: * 161: * @return the model location that represents the specified view location 162: */ 163: public abstract int viewToModel(GlyphView v, float x, float y, Shape a, 164: Position.Bias[] biasRet); 165: 166: /** 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). 172: * 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 178: * 179: * @return the span of the glyphs from location <code>p0</code> to 180: * location <code>p1</code>, possibly using TAB expansion 181: */ 182: public abstract float getSpan(GlyphView view, int p0, int p1, 183: TabExpander te, float x); 184: 185: 186: /** 187: * Returns the model location that should be used to place a caret when 188: * moving the caret through the document. 189: * 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 199: * 200: * @return the location within the document that should be used to place the 201: * caret when moving the caret around the document 202: * 203: * @throws BadLocationException if <code>pos</code> is an invalid model 204: * location 205: * @throws IllegalArgumentException if <code>d</code> is invalid 206: */ 207: public int getNextVisualPositionFrom(GlyphView v, int pos, Position.Bias b, 208: Shape a, int direction, 209: Position.Bias[] biasRet) 210: throws BadLocationException 211: 212: { 213: int result = pos; 214: switch (direction) 215: { 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; 228: } 229: return result; 230: } 231: 232: /** 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. 237: * 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 241: * 242: * @return a painter that can be used to render the specified glyph view 243: */ 244: public GlyphPainter getPainter(GlyphView v, int p0, int p1) 245: { 246: return this; 247: } 248: } 249: 250: /** 251: * The default <code>GlyphPainter</code> used in <code>GlyphView</code>. 252: */ 253: static class DefaultGlyphPainter extends GlyphPainter 254: { 255: /** 256: * Returns the full height of the rendered text. 257: * 258: * @return the full height of the rendered text 259: */ 260: public float getHeight(GlyphView view) 261: { 262: Font font = view.getFont(); 263: FontMetrics metrics = Toolkit.getDefaultToolkit().getFontMetrics(font); 264: float height = metrics.getHeight(); 265: return height; 266: } 267: 268: /** 269: * Paints the glyphs. 270: * 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 276: */ 277: public void paint(GlyphView view, Graphics g, Shape a, int p0, 278: int p1) 279: { 280: int height = (int) getHeight(view); 281: Segment txt = view.getText(p0, p1); 282: Rectangle bounds = a.getBounds(); 283: 284: TabExpander tabEx = null; 285: View parent = view.getParent(); 286: if (parent instanceof TabExpander) 287: tabEx = (TabExpander) parent; 288: 289: // Fill the background of the text run. 290: Color background = view.getBackground(); 291: g.setColor(background); 292: int width = Utilities.getTabbedTextWidth(txt, g.getFontMetrics(), 293: bounds.x, tabEx, txt.offset); 294: g.fillRect(bounds.x, bounds.y, width, height); 295: 296: // Draw the actual text. 297: g.setColor(view.getForeground()); 298: g.setFont(view.getFont()); 299: if (view.isSuperscript()) 300: // TODO: Adjust font for superscripting. 301: Utilities.drawTabbedText(txt, bounds.x, bounds.y - height / 2, g, tabEx, 302: txt.offset); 303: else if (view.isSubscript()) 304: // TODO: Adjust font for subscripting. 305: Utilities.drawTabbedText(txt, bounds.x, bounds.y + height / 2, g, tabEx, 306: txt.offset); 307: else 308: Utilities.drawTabbedText(txt, bounds.x, bounds.y, g, tabEx, 309: txt.offset); 310: 311: if (view.isStikeThrough()) 312: { 313: int strikeHeight = (int) (getAscent(view) / 2); 314: g.drawLine(bounds.x, bounds.y + strikeHeight, bounds.height + width, 315: bounds.y + strikeHeight); 316: } 317: if (view.isUnderline()) 318: { 319: int lineHeight = (int) getAscent(view); 320: g.drawLine(bounds.x, bounds.y + lineHeight, bounds.height + width, 321: bounds.y + lineHeight); 322: } 323: } 324: 325: /** 326: * Maps a position in the document into the coordinate space of the View. 327: * The output rectangle usually reflects the font height but has a width 328: * of zero. 329: * 330: * @param view the glyph view 331: * @param pos the position of the character in the model 332: * @param a the area that is occupied by the view 333: * @param b either {@link Position.Bias#Forward} or 334: * {@link Position.Bias#Backward} depending on the preferred 335: * direction bias. If <code>null</code> this defaults to 336: * <code>Position.Bias.Forward</code> 337: * 338: * @return a rectangle that gives the location of the document position 339: * inside the view coordinate space 340: * 341: * @throws BadLocationException if <code>pos</code> is invalid 342: * @throws IllegalArgumentException if b is not one of the above listed 343: * valid values 344: */ 345: public Shape modelToView(GlyphView view, int pos, Position.Bias b, 346: Shape a) 347: throws BadLocationException 348: { 349: Element el = view.getElement(); 350: Font font = view.getFont(); 351: FontMetrics fm = view.getContainer().getFontMetrics(font); 352: Segment txt = view.getText(el.getStartOffset(), pos); 353: int width = fm.charsWidth(txt.array, txt.offset, txt.count); 354: int height = fm.getHeight(); 355: Rectangle bounds = a.getBounds(); 356: Rectangle result = new Rectangle(bounds.x + width, bounds.y, 357: bounds.x + width, height); 358: return result; 359: } 360: 361: /** 362: * Determine the span of the glyphs from location <code>p0</code> to 363: * location <code>p1</code>. If <code>te</code> is not <code>null</code>, 364: * then TABs are expanded using this <code>TabExpander</code>. 365: * The parameter <code>x</code> is the location at which the view is 366: * located (this is important when using TAB expansion). 367: * 368: * @param view the glyph view 369: * @param p0 the starting location in the document model 370: * @param p1 the end location in the document model 371: * @param te the tab expander to use 372: * @param x the location at which the view is located 373: * 374: * @return the span of the glyphs from location <code>p0</code> to 375: * location <code>p1</code>, possibly using TAB expansion 376: */ 377: public float getSpan(GlyphView view, int p0, int p1, 378: TabExpander te, float x) 379: { 380: Element el = view.getElement(); 381: Font font = view.getFont(); 382: FontMetrics fm = Toolkit.getDefaultToolkit().getFontMetrics(font); 383: Segment txt = view.getText(p0, p1); 384: int span = Utilities.getTabbedTextWidth(txt, fm, (int) x, te, p0); 385: return span; 386: } 387: 388: /** 389: * Returns the ascent of the text run that is rendered by this 390: * <code>GlyphPainter</code>. 391: * 392: * @param v the glyph view 393: * 394: * @return the ascent of the text run that is rendered by this 395: * <code>GlyphPainter</code> 396: * 397: * @see FontMetrics#getAscent() 398: */ 399: public float getAscent(GlyphView v) 400: { 401: Font font = v.getFont(); 402: FontMetrics fm = v.getContainer().getFontMetrics(font); 403: return fm.getAscent(); 404: } 405: 406: /** 407: * Returns the descent of the text run that is rendered by this 408: * <code>GlyphPainter</code>. 409: * 410: * @param v the glyph view 411: * 412: * @return the descent of the text run that is rendered by this 413: * <code>GlyphPainter</code> 414: * 415: * @see FontMetrics#getDescent() 416: */ 417: public float getDescent(GlyphView v) 418: { 419: Font font = v.getFont(); 420: FontMetrics fm = v.getContainer().getFontMetrics(font); 421: return fm.getDescent(); 422: } 423: 424: /** 425: * Determines the model offset, so that the text between <code>p0</code> 426: * and this offset fits within the span starting at <code>x</code> with 427: * the length of <code>len</code>. 428: * 429: * @param v the glyph view 430: * @param p0 the starting offset in the model 431: * @param x the start location in the view 432: * @param len the length of the span in the view 433: */ 434: public int getBoundedPosition(GlyphView v, int p0, float x, float len) 435: { 436: TabExpander te = v.getTabExpander(); 437: Segment txt = v.getText(p0, v.getEndOffset()); 438: Font font = v.getFont(); 439: FontMetrics fm = v.getContainer().getFontMetrics(font); 440: int pos = Utilities.getTabbedTextOffset(txt, fm, (int) x, 441: (int) (x + len), te, p0, false); 442: return pos; 443: } 444: 445: /** 446: * Maps a visual position into a document location. 447: * 448: * @param v the glyph view 449: * @param x the X coordinate of the visual position 450: * @param y the Y coordinate of the visual position 451: * @param a the allocated region 452: * @param biasRet filled with the bias of the model location on method exit 453: * 454: * @return the model location that represents the specified view location 455: */ 456: public int viewToModel(GlyphView v, float x, float y, Shape a, 457: Bias[] biasRet) 458: { 459: Rectangle b = a.getBounds(); 460: assert b.contains(x, y) : "The coordinates are expected to be within the " 461: + "view's bounds: x=" + x + ", y=" + y 462: + "a=" + a; 463: int pos = getBoundedPosition(v, v.getStartOffset(), b.x, x - b.x); 464: return pos; 465: } 466: } 467: 468: /** 469: * The GlyphPainer used for painting the glyphs. 470: */ 471: GlyphPainter glyphPainter; 472: 473: /** 474: * The start offset within the document for this view. 475: */ 476: int startOffset; 477: 478: /** 479: * The end offset within the document for this view. 480: */ 481: int endOffset; 482: 483: /** 484: * Creates a new <code>GlyphView</code> for the given <code>Element</code>. 485: * 486: * @param element the element that is rendered by this GlyphView 487: */ 488: public GlyphView(Element element) 489: { 490: super(element); 491: startOffset = element.getStartOffset(); 492: endOffset = element.getEndOffset(); 493: } 494: 495: /** 496: * Returns the <code>GlyphPainter</code> that is used by this 497: * <code>GlyphView</code>. If no <code>GlyphPainer</code> has been installed 498: * <code>null</code> is returned. 499: * 500: * @return the glyph painter that is used by this 501: * glyph view or <code>null</code> if no glyph painter has been 502: * installed 503: */ 504: public GlyphPainter getGlyphPainter() 505: { 506: return glyphPainter; 507: } 508: 509: /** 510: * Sets the {@link GlyphPainter} to be used for this <code>GlyphView</code>. 511: * 512: * @param painter the glyph painter to be used for this glyph view 513: */ 514: public void setGlyphPainter(GlyphPainter painter) 515: { 516: glyphPainter = painter; 517: } 518: 519: /** 520: * Checks if a <code>GlyphPainer</code> is installed. If this is not the 521: * case, a default painter is installed. 522: */ 523: protected void checkPainter() 524: { 525: if (glyphPainter == null) 526: glyphPainter = new DefaultGlyphPainter(); 527: } 528: 529: /** 530: * Renders the <code>Element</code> that is associated with this 531: * <code>View</code>. 532: * 533: * @param g the <code>Graphics</code> context to render to 534: * @param a the allocated region for the <code>Element</code> 535: */ 536: public void paint(Graphics g, Shape a) 537: { 538: Element el = getElement(); 539: checkPainter(); 540: getGlyphPainter().paint(this, g, a, el.getStartOffset(), 541: el.getEndOffset()); 542: } 543: 544: 545: /** 546: * Returns the preferred span of the content managed by this 547: * <code>View</code> along the specified <code>axis</code>. 548: * 549: * @param axis the axis 550: * 551: * @return the preferred span of this <code>View</code>. 552: */ 553: public float getPreferredSpan(int axis) 554: { 555: float span = 0; 556: checkPainter(); 557: GlyphPainter painter = getGlyphPainter(); 558: if (axis == X_AXIS) 559: { 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); 567: } 568: else 569: span = painter.getHeight(this); 570: return span; 571: } 572: 573: /** 574: * Maps a position in the document into the coordinate space of the View. 575: * The output rectangle usually reflects the font height but has a width 576: * of zero. 577: * 578: * @param pos the position of the character in the model 579: * @param a the area that is occupied by the view 580: * @param b either {@link Position.Bias#Forward} or 581: * {@link Position.Bias#Backward} depending on the preferred 582: * direction bias. If <code>null</code> this defaults to 583: * <code>Position.Bias.Forward</code> 584: * 585: * @return a rectangle that gives the location of the document position 586: * inside the view coordinate space 587: * 588: * @throws BadLocationException if <code>pos</code> is invalid 589: * @throws IllegalArgumentException if b is not one of the above listed 590: * valid values 591: */ 592: public Shape modelToView(int pos, Shape a, Position.Bias b) 593: throws BadLocationException 594: { 595: GlyphPainter p = getGlyphPainter(); 596: return p.modelToView(this, pos, b, a); 597: } 598: 599: /** 600: * Maps coordinates from the <code>View</code>'s space into a position 601: * in the document model. 602: * 603: * @param x the x coordinate in the view space 604: * @param y the y coordinate in the view space 605: * @param a the allocation of this <code>View</code> 606: * @param b the bias to use 607: * 608: * @return the position in the document that corresponds to the screen 609: * coordinates <code>x, y</code> 610: */ 611: public int viewToModel(float x, float y, Shape a, Position.Bias[] b) 612: { 613: checkPainter(); 614: GlyphPainter painter = getGlyphPainter(); 615: return painter.viewToModel(this, x, y, a, b); 616: } 617: 618: /** 619: * Return the {@link TabExpander} to use. 620: * 621: * @return the {@link TabExpander} to use 622: */ 623: public TabExpander getTabExpander() 624: { 625: TabExpander te = null; 626: View parent = getParent(); 627: 628: if (parent instanceof TabExpander) 629: te = (TabExpander) parent; 630: 631: return te; 632: } 633: 634: /** 635: * Returns the preferred span of this view for tab expansion. 636: * 637: * @param x the location of the view 638: * @param te the tab expander to use 639: * 640: * @return the preferred span of this view for tab expansion 641: */ 642: public float getTabbedSpan(float x, TabExpander te) 643: { 644: Element el = getElement(); 645: return getGlyphPainter().getSpan(this, el.getStartOffset(), 646: el.getEndOffset(), te, x); 647: } 648: 649: /** 650: * Returns the span of a portion of the view. This is used in TAB expansion 651: * for fragments that don't contain TABs. 652: * 653: * @param p0 the start index 654: * @param p1 the end index 655: * 656: * @return the span of the specified portion of the view 657: */ 658: public float getPartialSpan(int p0, int p1) 659: { 660: Element el = getElement(); 661: Document doc = el.getDocument(); 662: Segment seg = new Segment(); 663: try 664: { 665: doc.getText(p0, p1 - p0, seg); 666: } 667: catch (BadLocationException ex) 668: { 669: AssertionError ae; 670: ae = new AssertionError("BadLocationException must not be thrown " 671: + "here"); 672: ae.initCause(ex); 673: throw ae; 674: } 675: FontMetrics fm = null; // Fetch font metrics somewhere. 676: return Utilities.getTabbedTextWidth(seg, fm, 0, null, p0); 677: } 678: 679: /** 680: * Returns the start offset in the document model of the portion 681: * of text that this view is responsible for. 682: * 683: * @return the start offset in the document model of the portion 684: * of text that this view is responsible for 685: */ 686: public int getStartOffset() 687: { 688: return startOffset; 689: } 690: 691: /** 692: * Returns the end offset in the document model of the portion 693: * of text that this view is responsible for. 694: * 695: * @return the end offset in the document model of the portion 696: * of text that this view is responsible for 697: */ 698: public int getEndOffset() 699: { 700: return endOffset; 701: } 702: 703: /** 704: * Returns the text segment that this view is responsible for. 705: * 706: * @param p0 the start index in the document model 707: * @param p1 the end index in the document model 708: * 709: * @return the text segment that this view is responsible for 710: */ 711: public Segment getText(int p0, int p1) 712: { 713: Segment txt = new Segment(); 714: try 715: { 716: getDocument().getText(p0, p1 - p0, txt); 717: } 718: catch (BadLocationException ex) 719: { 720: AssertionError ae; 721: ae = new AssertionError("BadLocationException should not be " 722: + "thrown here. p0 = " + p0 + ", p1 = " + p1); 723: ae.initCause(ex); 724: throw ae; 725: } 726: 727: return txt; 728: } 729: 730: /** 731: * Returns the font for the text run for which this <code>GlyphView</code> 732: * is responsible. 733: * 734: * @return the font for the text run for which this <code>GlyphView</code> 735: * is responsible 736: */ 737: public Font getFont() 738: { 739: Element el = getElement(); 740: AttributeSet atts = el.getAttributes(); 741: String family = StyleConstants.getFontFamily(atts); 742: int size = StyleConstants.getFontSize(atts); 743: int style = Font.PLAIN; 744: if (StyleConstants.isBold(atts)) 745: style |= Font.BOLD; 746: if (StyleConstants.isItalic(atts)) 747: style |= Font.ITALIC; 748: Font font = new Font(family, style, size); 749: return font; 750: } 751: 752: /** 753: * Returns the foreground color which should be used to paint the text. 754: * This is fetched from the associated element's text attributes using 755: * {@link StyleConstants#getForeground}. 756: * 757: * @return the foreground color which should be used to paint the text 758: */ 759: public Color getForeground() 760: { 761: Element el = getElement(); 762: AttributeSet atts = el.getAttributes(); 763: return StyleConstants.getForeground(atts); 764: } 765: 766: /** 767: * Returns the background color which should be used to paint the text. 768: * This is fetched from the associated element's text attributes using 769: * {@link StyleConstants#getBackground}. 770: * 771: * @return the background color which should be used to paint the text 772: */ 773: public Color getBackground() 774: { 775: Element el = getElement(); 776: AttributeSet atts = el.getAttributes(); 777: return StyleConstants.getBackground(atts); 778: } 779: 780: /** 781: * Determines whether the text should be rendered strike-through or not. This 782: * is determined using the method 783: * {@link StyleConstants#isStrikeThrough(AttributeSet)} on the element of 784: * this view. 785: * 786: * @return whether the text should be rendered strike-through or not 787: */ 788: public boolean isStikeThrough() 789: { 790: Element el = getElement(); 791: AttributeSet atts = el.getAttributes(); 792: return StyleConstants.isStrikeThrough(atts); 793: } 794: 795: /** 796: * Determines whether the text should be rendered as subscript or not. This 797: * is determined using the method 798: * {@link StyleConstants#isSubscript(AttributeSet)} on the element of 799: * this view. 800: * 801: * @return whether the text should be rendered as subscript or not 802: */ 803: public boolean isSubscript() 804: { 805: Element el = getElement(); 806: AttributeSet atts = el.getAttributes(); 807: return StyleConstants.isSubscript(atts); 808: } 809: 810: /** 811: * Determines whether the text should be rendered as superscript or not. This 812: * is determined using the method 813: * {@link StyleConstants#isSuperscript(AttributeSet)} on the element of 814: * this view. 815: * 816: * @return whether the text should be rendered as superscript or not 817: */ 818: public boolean isSuperscript() 819: { 820: Element el = getElement(); 821: AttributeSet atts = el.getAttributes(); 822: return StyleConstants.isSuperscript(atts); 823: } 824: 825: /** 826: * Determines whether the text should be rendered as underlined or not. This 827: * is determined using the method 828: * {@link StyleConstants#isUnderline(AttributeSet)} on the element of 829: * this view. 830: * 831: * @return whether the text should be rendered as underlined or not 832: */ 833: public boolean isUnderline() 834: { 835: Element el = getElement(); 836: AttributeSet atts = el.getAttributes(); 837: return StyleConstants.isUnderline(atts); 838: } 839: 840: /** 841: * Creates and returns a shallow clone of this GlyphView. This is used by 842: * the {@link #createFragment} and {@link #breakView} methods. 843: * 844: * @return a shallow clone of this GlyphView 845: */ 846: protected final Object clone() 847: { 848: try 849: { 850: return super.clone(); 851: } 852: catch (CloneNotSupportedException ex) 853: { 854: AssertionError err = new AssertionError("CloneNotSupportedException " 855: + "must not be thrown here"); 856: err.initCause(ex); 857: throw err; 858: } 859: } 860: 861: /** 862: * Tries to break the view near the specified view span <code>len</code>. 863: * The glyph view can only be broken in the X direction. For Y direction it 864: * returns itself. 865: * 866: * @param axis the axis for breaking, may be {@link View#X_AXIS} or 867: * {@link View#Y_AXIS} 868: * @param p0 the model location where the fragment should start 869: * @param pos the view position along the axis where the fragment starts 870: * @param len the desired length of the fragment view 871: * 872: * @return the fragment view, or <code>this</code> if breaking was not 873: * possible 874: */ 875: public View breakView(int axis, int p0, float pos, float len) 876: { 877: if (axis == Y_AXIS) 878: return this; 879: 880: checkPainter(); 881: GlyphPainter painter = getGlyphPainter(); 882: int breakLocation = painter.getBoundedPosition(this, p0, pos, len); 883: // Try to find a suitable line break. 884: BreakIterator lineBreaker = BreakIterator.getLineInstance(); 885: Segment txt = new Segment(); 886: try 887: { 888: getDocument().getText(getStartOffset(), getEndOffset(), txt); 889: } 890: catch (BadLocationException ex) 891: { 892: AssertionError err = new AssertionError("BadLocationException must not " 893: + "be thrown here."); 894: err.initCause(ex); 895: throw err; 896: } 897: lineBreaker.setText(txt); 898: int goodBreakLocation = lineBreaker.previous(); 899: if (goodBreakLocation != BreakIterator.DONE) 900: breakLocation = goodBreakLocation; 901: 902: View brokenView = createFragment(p0, breakLocation); 903: return brokenView; 904: } 905: 906: /** 907: * Determines how well the specified view location is suitable for inserting 908: * a line break. If <code>axis</code> is <code>View.Y_AXIS</code>, then 909: * this method forwards to the superclass, if <code>axis</code> is 910: * <code>View.X_AXIS</code> then this method returns 911: * {@link View#ExcellentBreakWeight} if there is a suitable break location 912: * (usually whitespace) within the specified view span, or 913: * {@link View#GoodBreakWeight} if not. 914: * 915: * @param axis the axis along which the break weight is requested 916: * @param pos the starting view location 917: * @param len the length of the span at which the view should be broken 918: * 919: * @return the break weight 920: */ 921: public int getBreakWeight(int axis, float pos, float len) 922: { 923: int weight; 924: if (axis == Y_AXIS) 925: weight = super.getBreakWeight(axis, pos, len); 926: else 927: { 928: // Determine the model locations at pos and pos + len. 929: int spanX = (int) getPreferredSpan(X_AXIS); 930: int spanY = (int) getPreferredSpan(Y_AXIS); 931: Rectangle dummyAlloc = new Rectangle(0, 0, spanX, spanY); 932: Position.Bias[] biasRet = new Position.Bias[1]; 933: int offset1 = viewToModel(pos, spanY / 2, dummyAlloc, biasRet); 934: int offset2 = viewToModel(pos, spanY / 2, dummyAlloc, biasRet); 935: Segment txt = getText(offset1, offset2); 936: BreakIterator lineBreaker = BreakIterator.getLineInstance(); 937: lineBreaker.setText(txt); 938: int breakLoc = lineBreaker.previous(); 939: if (breakLoc == offset1) 940: weight = View.BadBreakWeight; 941: else if(breakLoc == BreakIterator.DONE) 942: weight = View.GoodBreakWeight; 943: else 944: weight = View.ExcellentBreakWeight; 945: } 946: return weight; 947: } 948: 949: /** 950: * Receives notification that some text attributes have changed within the 951: * text fragment that this view is responsible for. This calls 952: * {@link View#preferenceChanged(View, boolean, boolean)} on the parent for 953: * both width and height. 954: * 955: * @param e the document event describing the change; not used here 956: * @param a the view allocation on screen; not used here 957: * @param vf the view factory; not used here 958: */ 959: public void changedUpdate(DocumentEvent e, Shape a, ViewFactory vf) 960: { 961: getParent().preferenceChanged(this, true, true); 962: } 963: 964: /** 965: * Receives notification that some text has been inserted within the 966: * text fragment that this view is responsible for. This calls 967: * {@link View#preferenceChanged(View, boolean, boolean)} on the parent for 968: * width. 969: * 970: * @param e the document event describing the change; not used here 971: * @param a the view allocation on screen; not used here 972: * @param vf the view factory; not used here 973: */ 974: public void insertUpdate(DocumentEvent e, Shape a, ViewFactory vf) 975: { 976: getParent().preferenceChanged(this, true, false); 977: } 978: 979: /** 980: * Receives notification that some text has been removed within the 981: * text fragment that this view is responsible for. This calls 982: * {@link View#preferenceChanged(View, boolean, boolean)} on the parent for 983: * width. 984: * 985: * @param e the document event describing the change; not used here 986: * @param a the view allocation on screen; not used here 987: * @param vf the view factory; not used here 988: */ 989: public void removeUpdate(DocumentEvent e, Shape a, ViewFactory vf) 990: { 991: getParent().preferenceChanged(this, true, false); 992: } 993: 994: /** 995: * Creates a fragment view of this view that starts at <code>p0</code> and 996: * ends at <code>p1</code>. 997: * 998: * @param p0 the start location for the fragment view 999: * @param p1 the end location for the fragment view 1000: * 1001: * @return the fragment view 1002: */ 1003: public View createFragment(int p0, int p1) 1004: { 1005: GlyphView fragment = (GlyphView) clone(); 1006: fragment.startOffset = p0; 1007: fragment.endOffset = p1; 1008: return fragment; 1009: } 1010: 1011: /** 1012: * Returns the alignment of this view along the specified axis. For the Y 1013: * axis this is <code>(height - descent) / height</code> for the used font, 1014: * so that it is aligned along the baseline. 1015: * For the X axis the superclass is called. 1016: */ 1017: public float getAlignment(int axis) 1018: { 1019: float align; 1020: if (axis == Y_AXIS) 1021: { 1022: checkPainter(); 1023: GlyphPainter painter = getGlyphPainter(); 1024: float height = painter.getHeight(this); 1025: float descent = painter.getDescent(this); 1026: align = (height - descent) / height; 1027: } 1028: else 1029: align = super.getAlignment(axis); 1030: 1031: return align; 1032: } 1033: 1034: /** 1035: * Returns the model location that should be used to place a caret when 1036: * moving the caret through the document. 1037: * 1038: * @param pos the current model location 1039: * @param bias the bias for <code>p</code> 1040: * @param a the allocated region for the glyph view 1041: * @param direction the direction from the current position; Must be one of 1042: * {@link SwingConstants#EAST}, {@link SwingConstants#WEST}, 1043: * {@link SwingConstants#NORTH} or {@link SwingConstants#SOUTH} 1044: * @param biasRet filled with the bias of the resulting location when method 1045: * returns 1046: * 1047: * @return the location within the document that should be used to place the 1048: * caret when moving the caret around the document 1049: * 1050: * @throws BadLocationException if <code>pos</code> is an invalid model 1051: * location 1052: * @throws IllegalArgumentException if <code>d</code> is invalid 1053: */ 1054: public int getNextVisualPositionFrom(int pos, Position.Bias bias, Shape a, 1055: int direction, Position.Bias[] biasRet) 1056: throws BadLocationException 1057: { 1058: checkPainter(); 1059: GlyphPainter painter = getGlyphPainter(); 1060: return painter.getNextVisualPositionFrom(this, pos, bias, a, direction, 1061: biasRet); 1062: } 1063: }
GNU Classpath (0.19) |