GNU Classpath (0.18) | ||
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: 48: /** 49: * Renders a run of styled text. This {@link View} subclass paints the 50: * characters of the <code>Element</code> it is responsible for using 51: * the style information from that <code>Element</code>. 52: * 53: * @author Roman Kennke (roman@kennke.org) 54: */ 55: public class GlyphView 56: extends View 57: implements TabableView, Cloneable 58: { 59: 60: /** 61: * An abstract base implementation for a glyph painter for 62: * <code>GlyphView</code>. 63: */ 64: public abstract static class GlyphPainter 65: { 66: /** 67: * Creates a new <code>GlyphPainer</code>. 68: */ 69: public GlyphPainter() 70: { 71: } 72: 73: /** 74: * Returns the full height of the rendered text. 75: * 76: * @return the full height of the rendered text 77: */ 78: public abstract float getHeight(GlyphView view); 79: 80: /** 81: * Paints the glyphs. 82: * 83: * @param view the glyph view to paint 84: * @param g the graphics context to use for painting 85: * @param a the allocation of the glyph view 86: * @param p0 the start position (in the model) from which to paint 87: * @param p1 the end position (in the model) to which to paint 88: */ 89: public abstract void paint(GlyphView view, Graphics g, Shape a, int p0, 90: int p1); 91: 92: /** 93: * Maps a position in the document into the coordinate space of the View. 94: * The output rectangle usually reflects the font height but has a width 95: * of zero. 96: * 97: * @param view the glyph view 98: * @param pos the position of the character in the model 99: * @param a the area that is occupied by the view 100: * @param bias either {@link Position.Bias.Forward} or 101: * {@link Position.Bias.Backward} depending on the preferred 102: * direction bias. If <code>null</code> this defaults to 103: * <code>Position.Bias.Forward</code> 104: * 105: * @return a rectangle that gives the location of the document position 106: * inside the view coordinate space 107: * 108: * @throws BadLocationException if <code>pos</code> is invalid 109: * @throws IllegalArgumentException if b is not one of the above listed 110: * valid values 111: */ 112: public abstract Shape modelToView(GlyphView view, int pos, Position.Bias b, 113: Shape a) 114: throws BadLocationException; 115: 116: /** 117: * Determine the span of the glyphs from location <code>p0</code> to 118: * location <code>p1</code>. If <code>te</code> is not <code>null</code>, 119: * then TABs are expanded using this <code>TabExpander</code>. 120: * The parameter <code>x</code> is the location at which the view is 121: * located (this is important when using TAB expansion). 122: * 123: * @param view the glyph view 124: * @param p0 the starting location in the document model 125: * @param p0 the end location in the document model 126: * @param te the tab expander to use 127: * @param x the location at which the view is located 128: * 129: * @return the span of the glyphs from location <code>p0</code> to 130: * location <code>p1</code>, possibly using TAB expansion 131: */ 132: public abstract float getSpan(GlyphView view, int p0, int p1, 133: TabExpander te, float x); 134: 135: } 136: 137: /** 138: * The default <code>GlyphPainter</code> used in <code>GlyphView</code>. 139: */ 140: static class DefaultGlyphPainter extends GlyphPainter 141: { 142: /** 143: * Returns the full height of the rendered text. 144: * 145: * @return the full height of the rendered text 146: */ 147: public float getHeight(GlyphView view) 148: { 149: Font font = view.getFont(); 150: FontMetrics metrics = view.getContainer().getFontMetrics(font); 151: float height = metrics.getHeight(); 152: return height; 153: } 154: 155: /** 156: * Paints the glyphs. 157: * 158: * @param view the glyph view to paint 159: * @param g the graphics context to use for painting 160: * @param a the allocation of the glyph view 161: * @param p0 the start position (in the model) from which to paint 162: * @param p1 the end position (in the model) to which to paint 163: */ 164: public void paint(GlyphView view, Graphics g, Shape a, int p0, 165: int p1) 166: { 167: int height = (int) getHeight(view); 168: Segment txt = view.getText(p0, p1); 169: Rectangle bounds = a.getBounds(); 170: 171: TabExpander tabEx = null; 172: View parent = view.getParent(); 173: if (parent instanceof TabExpander) 174: tabEx = (TabExpander) parent; 175: 176: // FIXME: Set character attributes like font-family, font-size, colors. 177: Color foreground = view.getForeground(); 178: g.setColor(foreground); 179: Utilities.drawTabbedText(txt, bounds.x, bounds.y, g, tabEx, 180: txt.offset); 181: } 182: 183: /** 184: * Maps a position in the document into the coordinate space of the View. 185: * The output rectangle usually reflects the font height but has a width 186: * of zero. 187: * 188: * @param view the glyph view 189: * @param pos the position of the character in the model 190: * @param a the area that is occupied by the view 191: * @param bias either {@link Position.Bias.Forward} or 192: * {@link Position.Bias.Backward} depending on the preferred 193: * direction bias. If <code>null</code> this defaults to 194: * <code>Position.Bias.Forward</code> 195: * 196: * @return a rectangle that gives the location of the document position 197: * inside the view coordinate space 198: * 199: * @throws BadLocationException if <code>pos</code> is invalid 200: * @throws IllegalArgumentException if b is not one of the above listed 201: * valid values 202: */ 203: public Shape modelToView(GlyphView view, int pos, Position.Bias b, 204: Shape a) 205: throws BadLocationException 206: { 207: Element el = view.getElement(); 208: Font font = view.getFont(); 209: FontMetrics fm = view.getContainer().getFontMetrics(font); 210: Segment txt = view.getText(el.getStartOffset(), pos); 211: int width = fm.charsWidth(txt.array, txt.offset, txt.count); 212: int height = fm.getHeight(); 213: Rectangle bounds = a.getBounds(); 214: Rectangle result = new Rectangle(bounds.x + width, bounds.y, 215: bounds.x + width, height); 216: return result; 217: } 218: 219: /** 220: * Determine the span of the glyphs from location <code>p0</code> to 221: * location <code>p1</code>. If <code>te</code> is not <code>null</code>, 222: * then TABs are expanded using this <code>TabExpander</code>. 223: * The parameter <code>x</code> is the location at which the view is 224: * located (this is important when using TAB expansion). 225: * 226: * @param view the glyph view 227: * @param p0 the starting location in the document model 228: * @param p0 the end location in the document model 229: * @param te the tab expander to use 230: * @param x the location at which the view is located 231: * 232: * @return the span of the glyphs from location <code>p0</code> to 233: * location <code>p1</code>, possibly using TAB expansion 234: */ 235: public float getSpan(GlyphView view, int p0, int p1, 236: TabExpander te, float x) 237: { 238: Element el = view.getElement(); 239: Font font = view.getFont(); 240: FontMetrics fm = view.getContainer().getFontMetrics(font); 241: Segment txt = view.getText(p0, p1); 242: int span = Utilities.getTabbedTextWidth(txt, fm, (int) x, te, p0); 243: return span; 244: } 245: } 246: 247: /** 248: * The GlyphPainer used for painting the glyphs. 249: */ 250: GlyphPainter glyphPainter; 251: 252: /** 253: * Creates a new <code>GlyphView</code> for the given <code>Element</code>. 254: * 255: * @param element the element that is rendered by this GlyphView 256: */ 257: public GlyphView(Element element) 258: { 259: super(element); 260: } 261: 262: /** 263: * Returns the <code>GlyphPainter</code> that is used by this 264: * <code>GlyphView</code>. If no <code>GlyphPainer</code> has been installed 265: * <code>null</code> is returned. 266: * 267: * @return the glyph painter that is used by this 268: * glyph view or <code>null</code> if no glyph painter has been 269: * installed 270: */ 271: public GlyphPainter getGlyphPainter() 272: { 273: return glyphPainter; 274: } 275: 276: /** 277: * Sets the {@link GlyphPainter} to be used for this <code>GlyphView</code>. 278: * 279: * @param painter the glyph painter to be used for this glyph view 280: */ 281: public void setGlyphPainter(GlyphPainter painter) 282: { 283: glyphPainter = painter; 284: } 285: 286: /** 287: * Checks if a <code>GlyphPainer</code> is installed. If this is not the 288: * case, a default painter is installed. 289: */ 290: protected void checkPainter() 291: { 292: if (glyphPainter == null) 293: glyphPainter = new DefaultGlyphPainter(); 294: } 295: 296: /** 297: * Renders the <code>Element</code> that is associated with this 298: * <code>View</code>. 299: * 300: * @param g the <code>Graphics</code> context to render to 301: * @param a the allocated region for the <code>Element</code> 302: */ 303: public void paint(Graphics g, Shape a) 304: { 305: Element el = getElement(); 306: checkPainter(); 307: getGlyphPainter().paint(this, g, a, el.getStartOffset(), 308: el.getEndOffset()); 309: } 310: 311: 312: /** 313: * Returns the preferred span of the content managed by this 314: * <code>View</code> along the specified <code>axis</code>. 315: * 316: * @param axis the axis 317: * 318: * @return the preferred span of this <code>View</code>. 319: */ 320: public float getPreferredSpan(int axis) 321: { 322: Element el = getElement(); 323: checkPainter(); 324: GlyphPainter painter = getGlyphPainter(); 325: TabExpander tabEx = null; 326: View parent = getParent(); 327: if (parent instanceof TabExpander) 328: tabEx = (TabExpander) parent; 329: // FIXME: Figure out how to determine the x parameter. 330: float span = painter.getSpan(this, el.getStartOffset(), el.getEndOffset(), 331: tabEx, 0.F); 332: return span; 333: } 334: 335: /** 336: * Maps a position in the document into the coordinate space of the View. 337: * The output rectangle usually reflects the font height but has a width 338: * of zero. 339: * 340: * @param pos the position of the character in the model 341: * @param a the area that is occupied by the view 342: * @param b either {@link Position.Bias#Forward} or 343: * {@link Position.Bias#Backward} depending on the preferred 344: * direction bias. If <code>null</code> this defaults to 345: * <code>Position.Bias.Forward</code> 346: * 347: * @return a rectangle that gives the location of the document position 348: * inside the view coordinate space 349: * 350: * @throws BadLocationException if <code>pos</code> is invalid 351: * @throws IllegalArgumentException if b is not one of the above listed 352: * valid values 353: */ 354: public Shape modelToView(int pos, Shape a, Position.Bias b) 355: throws BadLocationException 356: { 357: GlyphPainter p = getGlyphPainter(); 358: return p.modelToView(this, pos, b, a); 359: } 360: 361: /** 362: * Maps coordinates from the <code>View</code>'s space into a position 363: * in the document model. 364: * 365: * @param x the x coordinate in the view space 366: * @param y the y coordinate in the view space 367: * @param a the allocation of this <code>View</code> 368: * @param b the bias to use 369: * 370: * @return the position in the document that corresponds to the screen 371: * coordinates <code>x, y</code> 372: */ 373: public int viewToModel(float x, float y, Shape a, Position.Bias[] b) 374: { 375: // FIXME: not implemented 376: return 0; 377: } 378: 379: /** 380: * Return the {@link TabExpander} to use. 381: * 382: * @return the {@link TabExpander} to use 383: */ 384: public TabExpander getTabExpander() 385: { 386: // TODO: Figure out if this is correct. 387: TabExpander te = null; 388: View parent = getParent(); 389: 390: if (parent instanceof ParagraphView) 391: te = (ParagraphView) parent; 392: 393: return te; 394: } 395: 396: /** 397: * Returns the preferred span of this view for tab expansion. 398: * 399: * @param x the location of the view 400: * @param te the tab expander to use 401: * 402: * @return the preferred span of this view for tab expansion 403: */ 404: public float getTabbedSpan(float x, TabExpander te) 405: { 406: Element el = getElement(); 407: return getGlyphPainter().getSpan(this, el.getStartOffset(), 408: el.getEndOffset(), te, x); 409: } 410: 411: /** 412: * Returns the span of a portion of the view. This is used in TAB expansion 413: * for fragments that don't contain TABs. 414: * 415: * @param p0 the start index 416: * @param p1 the end index 417: * 418: * @return the span of the specified portion of the view 419: */ 420: public float getPartialSpan(int p0, int p1) 421: { 422: Element el = getElement(); 423: Document doc = el.getDocument(); 424: Segment seg = new Segment(); 425: try 426: { 427: doc.getText(p0, p1 - p0, seg); 428: } 429: catch (BadLocationException ex) 430: { 431: throw new AssertionError("BadLocationException must not be thrown " 432: + "here"); 433: } 434: FontMetrics fm = null; // Fetch font metrics somewhere. 435: return Utilities.getTabbedTextWidth(seg, fm, 0, null, p0); 436: } 437: 438: /** 439: * Returns the starting offset in the document model of the portion 440: * of text that this view is responsible for. 441: * 442: * @return the starting offset in the document model of the portion 443: * of text that this view is responsible for 444: */ 445: public int getBeginIndex() 446: { 447: return getElement().getStartOffset(); 448: } 449: 450: /** 451: * Returns the end offset in the document model of the portion 452: * of text that this view is responsible for. 453: * 454: * @return the end offset in the document model of the portion 455: * of text that this view is responsible for 456: */ 457: public int getEndIndex() 458: { 459: return getElement().getEndOffset(); 460: } 461: 462: /** 463: * Returns the text segment that this view is responsible for. 464: * 465: * @param p0 the start index in the document model 466: * @param p1 the end index in the document model 467: * 468: * @return the text segment that this view is responsible for 469: */ 470: public Segment getText(int p0, int p1) 471: { 472: Segment txt = new Segment(); 473: try 474: { 475: getDocument().getText(p0, p1 - p0, txt); 476: } 477: catch (BadLocationException ex) 478: { 479: throw new AssertionError("BadLocationException should not be " 480: + "thrown here. p0 = " + p0 + ", p1 = " + p1); 481: } 482: 483: return txt; 484: } 485: 486: /** 487: * Returns the font for the text run for which this <code>GlyphView</code> 488: * is responsible. 489: * 490: * @return the font for the text run for which this <code>GlyphView</code> 491: * is responsible 492: */ 493: public Font getFont() 494: { 495: Element el = getElement(); 496: AttributeSet atts = el.getAttributes(); 497: String family = StyleConstants.getFontFamily(atts); 498: int size = StyleConstants.getFontSize(atts); 499: int style = Font.PLAIN; 500: if (StyleConstants.isBold(atts)) 501: style |= Font.BOLD; 502: if (StyleConstants.isItalic(atts)) 503: style |= Font.ITALIC; 504: Font font = new Font(family, style, size); 505: return font; 506: } 507: 508: /** 509: * Returns the foreground color which should be used to paint the text. 510: * This is fetched from the associated element's text attributes using 511: * {@link StyleConstants#getForeground}. 512: * 513: * @return the foreground color which should be used to paint the text 514: */ 515: public Color getForeground() 516: { 517: Element el = getElement(); 518: AttributeSet atts = el.getAttributes(); 519: return StyleConstants.getForeground(atts); 520: } 521: }
GNU Classpath (0.18) |