Home » openjdk-7 » javax » swing » text » [javadoc | source]

    1   /*
    2    * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   package javax.swing.text;
   26   
   27   import java.util.Vector;
   28   import java.util.Properties;
   29   import java.awt;
   30   import javax.swing.event;
   31   
   32   /**
   33    * Implements View interface for a simple multi-line text view
   34    * that has text in one font and color.  The view represents each
   35    * child element as a line of text.
   36    *
   37    * @author  Timothy Prinzing
   38    * @see     View
   39    */
   40   public class PlainView extends View implements TabExpander {
   41   
   42       /**
   43        * Constructs a new PlainView wrapped on an element.
   44        *
   45        * @param elem the element
   46        */
   47       public PlainView(Element elem) {
   48           super(elem);
   49       }
   50   
   51       /**
   52        * Returns the tab size set for the document, defaulting to 8.
   53        *
   54        * @return the tab size
   55        */
   56       protected int getTabSize() {
   57           Integer i = (Integer) getDocument().getProperty(PlainDocument.tabSizeAttribute);
   58           int size = (i != null) ? i.intValue() : 8;
   59           return size;
   60       }
   61   
   62       /**
   63        * Renders a line of text, suppressing whitespace at the end
   64        * and expanding any tabs.  This is implemented to make calls
   65        * to the methods <code>drawUnselectedText</code> and
   66        * <code>drawSelectedText</code> so that the way selected and
   67        * unselected text are rendered can be customized.
   68        *
   69        * @param lineIndex the line to draw >= 0
   70        * @param g the <code>Graphics</code> context
   71        * @param x the starting X position >= 0
   72        * @param y the starting Y position >= 0
   73        * @see #drawUnselectedText
   74        * @see #drawSelectedText
   75        */
   76       protected void drawLine(int lineIndex, Graphics g, int x, int y) {
   77           Element line = getElement().getElement(lineIndex);
   78           Element elem;
   79   
   80           try {
   81               if (line.isLeaf()) {
   82                   drawElement(lineIndex, line, g, x, y);
   83               } else {
   84                   // this line contains the composed text.
   85                   int count = line.getElementCount();
   86                   for(int i = 0; i < count; i++) {
   87                       elem = line.getElement(i);
   88                       x = drawElement(lineIndex, elem, g, x, y);
   89                   }
   90               }
   91           } catch (BadLocationException e) {
   92               throw new StateInvariantError("Can't render line: " + lineIndex);
   93           }
   94       }
   95   
   96       private int drawElement(int lineIndex, Element elem, Graphics g, int x, int y) throws BadLocationException {
   97           int p0 = elem.getStartOffset();
   98           int p1 = elem.getEndOffset();
   99           p1 = Math.min(getDocument().getLength(), p1);
  100   
  101           if (lineIndex == 0) {
  102               x += firstLineOffset;
  103           }
  104           AttributeSet attr = elem.getAttributes();
  105           if (Utilities.isComposedTextAttributeDefined(attr)) {
  106               g.setColor(unselected);
  107               x = Utilities.drawComposedText(this, attr, g, x, y,
  108                                           p0-elem.getStartOffset(),
  109                                           p1-elem.getStartOffset());
  110           } else {
  111               if (sel0 == sel1 || selected == unselected) {
  112                   // no selection, or it is invisible
  113                   x = drawUnselectedText(g, x, y, p0, p1);
  114               } else if ((p0 >= sel0 && p0 <= sel1) && (p1 >= sel0 && p1 <= sel1)) {
  115                   x = drawSelectedText(g, x, y, p0, p1);
  116               } else if (sel0 >= p0 && sel0 <= p1) {
  117                   if (sel1 >= p0 && sel1 <= p1) {
  118                       x = drawUnselectedText(g, x, y, p0, sel0);
  119                       x = drawSelectedText(g, x, y, sel0, sel1);
  120                       x = drawUnselectedText(g, x, y, sel1, p1);
  121                   } else {
  122                       x = drawUnselectedText(g, x, y, p0, sel0);
  123                       x = drawSelectedText(g, x, y, sel0, p1);
  124                   }
  125               } else if (sel1 >= p0 && sel1 <= p1) {
  126                   x = drawSelectedText(g, x, y, p0, sel1);
  127                   x = drawUnselectedText(g, x, y, sel1, p1);
  128               } else {
  129                   x = drawUnselectedText(g, x, y, p0, p1);
  130               }
  131           }
  132   
  133           return x;
  134       }
  135   
  136       /**
  137        * Renders the given range in the model as normal unselected
  138        * text.  Uses the foreground or disabled color to render the text.
  139        *
  140        * @param g the graphics context
  141        * @param x the starting X coordinate >= 0
  142        * @param y the starting Y coordinate >= 0
  143        * @param p0 the beginning position in the model >= 0
  144        * @param p1 the ending position in the model >= 0
  145        * @return the X location of the end of the range >= 0
  146        * @exception BadLocationException if the range is invalid
  147        */
  148       protected int drawUnselectedText(Graphics g, int x, int y,
  149                                        int p0, int p1) throws BadLocationException {
  150           g.setColor(unselected);
  151           Document doc = getDocument();
  152           Segment s = SegmentCache.getSharedSegment();
  153           doc.getText(p0, p1 - p0, s);
  154           int ret = Utilities.drawTabbedText(this, s, x, y, g, this, p0);
  155           SegmentCache.releaseSharedSegment(s);
  156           return ret;
  157       }
  158   
  159       /**
  160        * Renders the given range in the model as selected text.  This
  161        * is implemented to render the text in the color specified in
  162        * the hosting component.  It assumes the highlighter will render
  163        * the selected background.
  164        *
  165        * @param g the graphics context
  166        * @param x the starting X coordinate >= 0
  167        * @param y the starting Y coordinate >= 0
  168        * @param p0 the beginning position in the model >= 0
  169        * @param p1 the ending position in the model >= 0
  170        * @return the location of the end of the range
  171        * @exception BadLocationException if the range is invalid
  172        */
  173       protected int drawSelectedText(Graphics g, int x,
  174                                      int y, int p0, int p1) throws BadLocationException {
  175           g.setColor(selected);
  176           Document doc = getDocument();
  177           Segment s = SegmentCache.getSharedSegment();
  178           doc.getText(p0, p1 - p0, s);
  179           int ret = Utilities.drawTabbedText(this, s, x, y, g, this, p0);
  180           SegmentCache.releaseSharedSegment(s);
  181           return ret;
  182       }
  183   
  184       /**
  185        * Gives access to a buffer that can be used to fetch
  186        * text from the associated document.
  187        *
  188        * @return the buffer
  189        */
  190       protected final Segment getLineBuffer() {
  191           if (lineBuffer == null) {
  192               lineBuffer = new Segment();
  193           }
  194           return lineBuffer;
  195       }
  196   
  197       /**
  198        * Checks to see if the font metrics and longest line
  199        * are up-to-date.
  200        *
  201        * @since 1.4
  202        */
  203       protected void updateMetrics() {
  204           Component host = getContainer();
  205           Font f = host.getFont();
  206           if (font != f) {
  207               // The font changed, we need to recalculate the
  208               // longest line.
  209               calculateLongestLine();
  210               tabSize = getTabSize() * metrics.charWidth('m');
  211           }
  212       }
  213   
  214       // ---- View methods ----------------------------------------------------
  215   
  216       /**
  217        * Determines the preferred span for this view along an
  218        * axis.
  219        *
  220        * @param axis may be either View.X_AXIS or View.Y_AXIS
  221        * @return   the span the view would like to be rendered into >= 0.
  222        *           Typically the view is told to render into the span
  223        *           that is returned, although there is no guarantee.
  224        *           The parent may choose to resize or break the view.
  225        * @exception IllegalArgumentException for an invalid axis
  226        */
  227       public float getPreferredSpan(int axis) {
  228           updateMetrics();
  229           switch (axis) {
  230           case View.X_AXIS:
  231               return getLineWidth(longLine);
  232           case View.Y_AXIS:
  233               return getElement().getElementCount() * metrics.getHeight();
  234           default:
  235               throw new IllegalArgumentException("Invalid axis: " + axis);
  236           }
  237       }
  238   
  239       /**
  240        * Renders using the given rendering surface and area on that surface.
  241        * The view may need to do layout and create child views to enable
  242        * itself to render into the given allocation.
  243        *
  244        * @param g the rendering surface to use
  245        * @param a the allocated region to render into
  246        *
  247        * @see View#paint
  248        */
  249       public void paint(Graphics g, Shape a) {
  250           Shape originalA = a;
  251           a = adjustPaintRegion(a);
  252           Rectangle alloc = (Rectangle) a;
  253           tabBase = alloc.x;
  254           JTextComponent host = (JTextComponent) getContainer();
  255           Highlighter h = host.getHighlighter();
  256           g.setFont(host.getFont());
  257           sel0 = host.getSelectionStart();
  258           sel1 = host.getSelectionEnd();
  259           unselected = (host.isEnabled()) ?
  260               host.getForeground() : host.getDisabledTextColor();
  261           Caret c = host.getCaret();
  262           selected = c.isSelectionVisible() && h != null ?
  263                          host.getSelectedTextColor() : unselected;
  264           updateMetrics();
  265   
  266           // If the lines are clipped then we don't expend the effort to
  267           // try and paint them.  Since all of the lines are the same height
  268           // with this object, determination of what lines need to be repainted
  269           // is quick.
  270           Rectangle clip = g.getClipBounds();
  271           int fontHeight = metrics.getHeight();
  272           int heightBelow = (alloc.y + alloc.height) - (clip.y + clip.height);
  273           int heightAbove = clip.y - alloc.y;
  274           int linesBelow, linesAbove, linesTotal;
  275   
  276           if (fontHeight > 0) {
  277               linesBelow = Math.max(0, heightBelow / fontHeight);
  278               linesAbove = Math.max(0, heightAbove / fontHeight);
  279               linesTotal = alloc.height / fontHeight;
  280               if (alloc.height % fontHeight != 0) {
  281                   linesTotal++;
  282               }
  283           } else {
  284               linesBelow = linesAbove = linesTotal = 0;
  285           }
  286   
  287           // update the visible lines
  288           Rectangle lineArea = lineToRect(a, linesAbove);
  289           int y = lineArea.y + metrics.getAscent();
  290           int x = lineArea.x;
  291           Element map = getElement();
  292           int lineCount = map.getElementCount();
  293           int endLine = Math.min(lineCount, linesTotal - linesBelow);
  294           lineCount--;
  295           LayeredHighlighter dh = (h instanceof LayeredHighlighter) ?
  296                              (LayeredHighlighter)h : null;
  297           for (int line = linesAbove; line < endLine; line++) {
  298               if (dh != null) {
  299                   Element lineElement = map.getElement(line);
  300                   if (line == lineCount) {
  301                       dh.paintLayeredHighlights(g, lineElement.getStartOffset(),
  302                                                 lineElement.getEndOffset(),
  303                                                 originalA, host, this);
  304                   }
  305                   else {
  306                       dh.paintLayeredHighlights(g, lineElement.getStartOffset(),
  307                                                 lineElement.getEndOffset() - 1,
  308                                                 originalA, host, this);
  309                   }
  310               }
  311               drawLine(line, g, x, y);
  312               y += fontHeight;
  313               if (line == 0) {
  314                   // This should never really happen, in so far as if
  315                   // firstLineOffset is non 0, there should only be one
  316                   // line of text.
  317                   x -= firstLineOffset;
  318               }
  319           }
  320       }
  321   
  322       /**
  323        * Should return a shape ideal for painting based on the passed in
  324        * Shape <code>a</code>. This is useful if painting in a different
  325        * region. The default implementation returns <code>a</code>.
  326        */
  327       Shape adjustPaintRegion(Shape a) {
  328           return a;
  329       }
  330   
  331       /**
  332        * Provides a mapping from the document model coordinate space
  333        * to the coordinate space of the view mapped to it.
  334        *
  335        * @param pos the position to convert >= 0
  336        * @param a the allocated region to render into
  337        * @return the bounding box of the given position
  338        * @exception BadLocationException  if the given position does not
  339        *   represent a valid location in the associated document
  340        * @see View#modelToView
  341        */
  342       public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {
  343           // line coordinates
  344           Document doc = getDocument();
  345           Element map = getElement();
  346           int lineIndex = map.getElementIndex(pos);
  347           if (lineIndex < 0) {
  348               return lineToRect(a, 0);
  349           }
  350           Rectangle lineArea = lineToRect(a, lineIndex);
  351   
  352           // determine span from the start of the line
  353           tabBase = lineArea.x;
  354           Element line = map.getElement(lineIndex);
  355           int p0 = line.getStartOffset();
  356           Segment s = SegmentCache.getSharedSegment();
  357           doc.getText(p0, pos - p0, s);
  358           int xOffs = Utilities.getTabbedTextWidth(s, metrics, tabBase, this,p0);
  359           SegmentCache.releaseSharedSegment(s);
  360   
  361           // fill in the results and return
  362           lineArea.x += xOffs;
  363           lineArea.width = 1;
  364           lineArea.height = metrics.getHeight();
  365           return lineArea;
  366       }
  367   
  368       /**
  369        * Provides a mapping from the view coordinate space to the logical
  370        * coordinate space of the model.
  371        *
  372        * @param fx the X coordinate >= 0
  373        * @param fy the Y coordinate >= 0
  374        * @param a the allocated region to render into
  375        * @return the location within the model that best represents the
  376        *  given point in the view >= 0
  377        * @see View#viewToModel
  378        */
  379       public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) {
  380           // PENDING(prinz) properly calculate bias
  381           bias[0] = Position.Bias.Forward;
  382   
  383           Rectangle alloc = a.getBounds();
  384           Document doc = getDocument();
  385           int x = (int) fx;
  386           int y = (int) fy;
  387           if (y < alloc.y) {
  388               // above the area covered by this icon, so the the position
  389               // is assumed to be the start of the coverage for this view.
  390               return getStartOffset();
  391           } else if (y > alloc.y + alloc.height) {
  392               // below the area covered by this icon, so the the position
  393               // is assumed to be the end of the coverage for this view.
  394               return getEndOffset() - 1;
  395           } else {
  396               // positioned within the coverage of this view vertically,
  397               // so we figure out which line the point corresponds to.
  398               // if the line is greater than the number of lines contained, then
  399               // simply use the last line as it represents the last possible place
  400               // we can position to.
  401               Element map = doc.getDefaultRootElement();
  402               int fontHeight = metrics.getHeight();
  403               int lineIndex = (fontHeight > 0 ?
  404                                   Math.abs((y - alloc.y) / fontHeight) :
  405                                   map.getElementCount() - 1);
  406               if (lineIndex >= map.getElementCount()) {
  407                   return getEndOffset() - 1;
  408               }
  409               Element line = map.getElement(lineIndex);
  410               int dx = 0;
  411               if (lineIndex == 0) {
  412                   alloc.x += firstLineOffset;
  413                   alloc.width -= firstLineOffset;
  414               }
  415               if (x < alloc.x) {
  416                   // point is to the left of the line
  417                   return line.getStartOffset();
  418               } else if (x > alloc.x + alloc.width) {
  419                   // point is to the right of the line
  420                   return line.getEndOffset() - 1;
  421               } else {
  422                   // Determine the offset into the text
  423                   try {
  424                       int p0 = line.getStartOffset();
  425                       int p1 = line.getEndOffset() - 1;
  426                       Segment s = SegmentCache.getSharedSegment();
  427                       doc.getText(p0, p1 - p0, s);
  428                       tabBase = alloc.x;
  429                       int offs = p0 + Utilities.getTabbedTextOffset(s, metrics,
  430                                                                     tabBase, x, this, p0);
  431                       SegmentCache.releaseSharedSegment(s);
  432                       return offs;
  433                   } catch (BadLocationException e) {
  434                       // should not happen
  435                       return -1;
  436                   }
  437               }
  438           }
  439       }
  440   
  441       /**
  442        * Gives notification that something was inserted into the document
  443        * in a location that this view is responsible for.
  444        *
  445        * @param changes the change information from the associated document
  446        * @param a the current allocation of the view
  447        * @param f the factory to use to rebuild if the view has children
  448        * @see View#insertUpdate
  449        */
  450       public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
  451           updateDamage(changes, a, f);
  452       }
  453   
  454       /**
  455        * Gives notification that something was removed from the document
  456        * in a location that this view is responsible for.
  457        *
  458        * @param changes the change information from the associated document
  459        * @param a the current allocation of the view
  460        * @param f the factory to use to rebuild if the view has children
  461        * @see View#removeUpdate
  462        */
  463       public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
  464           updateDamage(changes, a, f);
  465       }
  466   
  467       /**
  468        * Gives notification from the document that attributes were changed
  469        * in a location that this view is responsible for.
  470        *
  471        * @param changes the change information from the associated document
  472        * @param a the current allocation of the view
  473        * @param f the factory to use to rebuild if the view has children
  474        * @see View#changedUpdate
  475        */
  476       public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
  477           updateDamage(changes, a, f);
  478       }
  479   
  480       /**
  481        * Sets the size of the view.  This should cause
  482        * layout of the view along the given axis, if it
  483        * has any layout duties.
  484        *
  485        * @param width the width >= 0
  486        * @param height the height >= 0
  487        */
  488       public void setSize(float width, float height) {
  489           super.setSize(width, height);
  490           updateMetrics();
  491       }
  492   
  493       // --- TabExpander methods ------------------------------------------
  494   
  495       /**
  496        * Returns the next tab stop position after a given reference position.
  497        * This implementation does not support things like centering so it
  498        * ignores the tabOffset argument.
  499        *
  500        * @param x the current position >= 0
  501        * @param tabOffset the position within the text stream
  502        *   that the tab occurred at >= 0.
  503        * @return the tab stop, measured in points >= 0
  504        */
  505       public float nextTabStop(float x, int tabOffset) {
  506           if (tabSize == 0) {
  507               return x;
  508           }
  509           int ntabs = (((int) x) - tabBase) / tabSize;
  510           return tabBase + ((ntabs + 1) * tabSize);
  511       }
  512   
  513       // --- local methods ------------------------------------------------
  514   
  515       /**
  516        * Repaint the region of change covered by the given document
  517        * event.  Damages the line that begins the range to cover
  518        * the case when the insert/remove is only on one line.
  519        * If lines are added or removed, damages the whole
  520        * view.  The longest line is checked to see if it has
  521        * changed.
  522        *
  523        * @since 1.4
  524        */
  525       protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f) {
  526           Component host = getContainer();
  527           updateMetrics();
  528           Element elem = getElement();
  529           DocumentEvent.ElementChange ec = changes.getChange(elem);
  530   
  531           Element[] added = (ec != null) ? ec.getChildrenAdded() : null;
  532           Element[] removed = (ec != null) ? ec.getChildrenRemoved() : null;
  533           if (((added != null) && (added.length > 0)) ||
  534               ((removed != null) && (removed.length > 0))) {
  535               // lines were added or removed...
  536               if (added != null) {
  537                   int currWide = getLineWidth(longLine);
  538                   for (int i = 0; i < added.length; i++) {
  539                       int w = getLineWidth(added[i]);
  540                       if (w > currWide) {
  541                           currWide = w;
  542                           longLine = added[i];
  543                       }
  544                   }
  545               }
  546               if (removed != null) {
  547                   for (int i = 0; i < removed.length; i++) {
  548                       if (removed[i] == longLine) {
  549                           calculateLongestLine();
  550                           break;
  551                       }
  552                   }
  553               }
  554               preferenceChanged(null, true, true);
  555               host.repaint();
  556           } else {
  557               Element map = getElement();
  558               int line = map.getElementIndex(changes.getOffset());
  559               damageLineRange(line, line, a, host);
  560               if (changes.getType() == DocumentEvent.EventType.INSERT) {
  561                   // check to see if the line is longer than current
  562                   // longest line.
  563                   int w = getLineWidth(longLine);
  564                   Element e = map.getElement(line);
  565                   if (e == longLine) {
  566                       preferenceChanged(null, true, false);
  567                   } else if (getLineWidth(e) > w) {
  568                       longLine = e;
  569                       preferenceChanged(null, true, false);
  570                   }
  571               } else if (changes.getType() == DocumentEvent.EventType.REMOVE) {
  572                   if (map.getElement(line) == longLine) {
  573                       // removed from longest line... recalc
  574                       calculateLongestLine();
  575                       preferenceChanged(null, true, false);
  576                   }
  577               }
  578           }
  579       }
  580   
  581       /**
  582        * Repaint the given line range.
  583        *
  584        * @param host the component hosting the view (used to call repaint)
  585        * @param a  the region allocated for the view to render into
  586        * @param line0 the starting line number to repaint.  This must
  587        *   be a valid line number in the model.
  588        * @param line1 the ending line number to repaint.  This must
  589        *   be a valid line number in the model.
  590        * @since 1.4
  591        */
  592       protected void damageLineRange(int line0, int line1, Shape a, Component host) {
  593           if (a != null) {
  594               Rectangle area0 = lineToRect(a, line0);
  595               Rectangle area1 = lineToRect(a, line1);
  596               if ((area0 != null) && (area1 != null)) {
  597                   Rectangle damage = area0.union(area1);
  598                   host.repaint(damage.x, damage.y, damage.width, damage.height);
  599               } else {
  600                   host.repaint();
  601               }
  602           }
  603       }
  604   
  605       /**
  606        * Determine the rectangle that represents the given line.
  607        *
  608        * @param a  the region allocated for the view to render into
  609        * @param line the line number to find the region of.  This must
  610        *   be a valid line number in the model.
  611        * @since 1.4
  612        */
  613       protected Rectangle lineToRect(Shape a, int line) {
  614           Rectangle r = null;
  615           updateMetrics();
  616           if (metrics != null) {
  617               Rectangle alloc = a.getBounds();
  618               if (line == 0) {
  619                   alloc.x += firstLineOffset;
  620                   alloc.width -= firstLineOffset;
  621               }
  622               r = new Rectangle(alloc.x, alloc.y + (line * metrics.getHeight()),
  623                                 alloc.width, metrics.getHeight());
  624           }
  625           return r;
  626       }
  627   
  628       /**
  629        * Iterate over the lines represented by the child elements
  630        * of the element this view represents, looking for the line
  631        * that is the longest.  The <em>longLine</em> variable is updated to
  632        * represent the longest line contained.  The <em>font</em> variable
  633        * is updated to indicate the font used to calculate the
  634        * longest line.
  635        */
  636       private void calculateLongestLine() {
  637           Component c = getContainer();
  638           font = c.getFont();
  639           metrics = c.getFontMetrics(font);
  640           Document doc = getDocument();
  641           Element lines = getElement();
  642           int n = lines.getElementCount();
  643           int maxWidth = -1;
  644           for (int i = 0; i < n; i++) {
  645               Element line = lines.getElement(i);
  646               int w = getLineWidth(line);
  647               if (w > maxWidth) {
  648                   maxWidth = w;
  649                   longLine = line;
  650               }
  651           }
  652       }
  653   
  654       /**
  655        * Calculate the width of the line represented by
  656        * the given element.  It is assumed that the font
  657        * and font metrics are up-to-date.
  658        */
  659       private int getLineWidth(Element line) {
  660           if (line == null) {
  661               return 0;
  662           }
  663           int p0 = line.getStartOffset();
  664           int p1 = line.getEndOffset();
  665           int w;
  666           Segment s = SegmentCache.getSharedSegment();
  667           try {
  668               line.getDocument().getText(p0, p1 - p0, s);
  669               w = Utilities.getTabbedTextWidth(s, metrics, tabBase, this, p0);
  670           } catch (BadLocationException ble) {
  671               w = 0;
  672           }
  673           SegmentCache.releaseSharedSegment(s);
  674           return w;
  675       }
  676   
  677       // --- member variables -----------------------------------------------
  678   
  679       /**
  680        * Font metrics for the current font.
  681        */
  682       protected FontMetrics metrics;
  683   
  684       /**
  685        * The current longest line.  This is used to calculate
  686        * the preferred width of the view.  Since the calculation
  687        * is potentially expensive we try to avoid it by stashing
  688        * which line is currently the longest.
  689        */
  690       Element longLine;
  691   
  692       /**
  693        * Font used to calculate the longest line... if this
  694        * changes we need to recalculate the longest line
  695        */
  696       Font font;
  697   
  698       Segment lineBuffer;
  699       int tabSize;
  700       int tabBase;
  701   
  702       int sel0;
  703       int sel1;
  704       Color unselected;
  705       Color selected;
  706   
  707       /**
  708        * Offset of where to draw the first character on the first line.
  709        * This is a hack and temporary until we can better address the problem
  710        * of text measuring. This field is actually never set directly in
  711        * PlainView, but by FieldView.
  712        */
  713       int firstLineOffset;
  714   
  715   }

Home » openjdk-7 » javax » swing » text » [javadoc | source]