Source Code Cross Referenced for GlyphView.java in  » 6.0-JDK-Core » swing » javax » swing » text » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » swing » javax.swing.text 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001        /*
0002         * Copyright 1999-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004         *
0005         * This code is free software; you can redistribute it and/or modify it
0006         * under the terms of the GNU General Public License version 2 only, as
0007         * published by the Free Software Foundation.  Sun designates this
0008         * particular file as subject to the "Classpath" exception as provided
0009         * by Sun in the LICENSE file that accompanied this code.
0010         *
0011         * This code is distributed in the hope that it will be useful, but WITHOUT
0012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014         * version 2 for more details (a copy is included in the LICENSE file that
0015         * accompanied this code).
0016         *
0017         * You should have received a copy of the GNU General Public License version
0018         * 2 along with this work; if not, write to the Free Software Foundation,
0019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020         *
0021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022         * CA 95054 USA or visit www.sun.com if you need additional information or
0023         * have any questions.
0024         */
0025        package javax.swing.text;
0026
0027        import java.awt.*;
0028        import java.text.BreakIterator;
0029        import javax.swing.event.*;
0030        import java.util.BitSet;
0031
0032        import sun.swing.SwingUtilities2;
0033
0034        /**
0035         * A GlyphView is a styled chunk of text that represents a view
0036         * mapped over an element in the text model. This view is generally 
0037         * responsible for displaying text glyphs using character level 
0038         * attributes in some way.
0039         * An implementation of the GlyphPainter class is used to do the
0040         * actual rendering and model/view translations.  This separates
0041         * rendering from layout and management of the association with
0042         * the model.
0043         * <p>
0044         * The view supports breaking for the purpose of formatting.   
0045         * The fragments produced by breaking share the view that has 
0046         * primary responsibility for the element (i.e. they are nested 
0047         * classes and carry only a small amount of state of their own) 
0048         * so they can share its resources.
0049         * <p>
0050         * Since this view 
0051         * represents text that may have tabs embedded in it, it implements the
0052         * <code>TabableView</code> interface.  Tabs will only be
0053         * expanded if this view is embedded in a container that does
0054         * tab expansion.  ParagraphView is an example of a container
0055         * that does tab expansion.
0056         * <p>
0057         *
0058         * @since 1.3
0059         *
0060         * @author  Timothy Prinzing
0061         * @version 1.49 05/05/07
0062         */
0063        public class GlyphView extends View implements  TabableView, Cloneable {
0064
0065            /**
0066             * Constructs a new view wrapped on an element.
0067             *
0068             * @param elem the element
0069             */
0070            public GlyphView(Element elem) {
0071                super (elem);
0072                offset = 0;
0073                length = 0;
0074                Element parent = elem.getParentElement();
0075                AttributeSet attr = elem.getAttributes();
0076
0077                //         if there was an implied CR
0078                impliedCR = (attr != null
0079                        && attr.getAttribute(IMPLIED_CR) != null &&
0080                        //         if this is non-empty paragraph
0081                        parent != null && parent.getElementCount() > 1);
0082                skipWidth = elem.getName().equals("br");
0083            }
0084
0085            /**
0086             * Creates a shallow copy.  This is used by the
0087             * createFragment and breakView methods.
0088             *
0089             * @return the copy
0090             */
0091            protected final Object clone() {
0092                Object o;
0093                try {
0094                    o = super .clone();
0095                } catch (CloneNotSupportedException cnse) {
0096                    o = null;
0097                }
0098                return o;
0099            }
0100
0101            /**
0102             * Fetch the currently installed glyph painter.
0103             * If a painter has not yet been installed, and
0104             * a default was not yet needed, null is returned.
0105             */
0106            public GlyphPainter getGlyphPainter() {
0107                return painter;
0108            }
0109
0110            /**
0111             * Sets the painter to use for rendering glyphs.
0112             */
0113            public void setGlyphPainter(GlyphPainter p) {
0114                painter = p;
0115            }
0116
0117            /**
0118             * Fetch a reference to the text that occupies
0119             * the given range.  This is normally used by
0120             * the GlyphPainter to determine what characters
0121             * it should render glyphs for.
0122             *
0123             * @param p0  the starting document offset >= 0
0124             * @param p1  the ending document offset >= p0
0125             * @return    the <code>Segment</code> containing the text
0126             */
0127            public Segment getText(int p0, int p1) {
0128                // When done with the returned Segment it should be released by
0129                // invoking:
0130                //    SegmentCache.releaseSharedSegment(segment);
0131                Segment text = SegmentCache.getSharedSegment();
0132                try {
0133                    Document doc = getDocument();
0134                    doc.getText(p0, p1 - p0, text);
0135                } catch (BadLocationException bl) {
0136                    throw new StateInvariantError("GlyphView: Stale view: "
0137                            + bl);
0138                }
0139                return text;
0140            }
0141
0142            /**
0143             * Fetch the background color to use to render the
0144             * glyphs.  If there is no background color, null should
0145             * be returned.  This is implemented to call 
0146             * <code>StyledDocument.getBackground</code> if the associated
0147             * document is a styled document, otherwise it returns null.
0148             */
0149            public Color getBackground() {
0150                Document doc = getDocument();
0151                if (doc instanceof  StyledDocument) {
0152                    AttributeSet attr = getAttributes();
0153                    if (attr.isDefined(StyleConstants.Background)) {
0154                        return ((StyledDocument) doc).getBackground(attr);
0155                    }
0156                }
0157                return null;
0158            }
0159
0160            /**
0161             * Fetch the foreground color to use to render the
0162             * glyphs.  If there is no foreground color, null should
0163             * be returned.  This is implemented to call
0164             * <code>StyledDocument.getBackground</code> if the associated
0165             * document is a StyledDocument.  If the associated document
0166             * is not a StyledDocument, the associated components foreground
0167             * color is used.  If there is no associated component, null 
0168             * is returned.
0169             */
0170            public Color getForeground() {
0171                Document doc = getDocument();
0172                if (doc instanceof  StyledDocument) {
0173                    AttributeSet attr = getAttributes();
0174                    return ((StyledDocument) doc).getForeground(attr);
0175                }
0176                Component c = getContainer();
0177                if (c != null) {
0178                    return c.getForeground();
0179                }
0180                return null;
0181            }
0182
0183            /**
0184             * Fetch the font that the glyphs should be based
0185             * upon.  This is implemented to call
0186             * <code>StyledDocument.getFont</code> if the associated
0187             * document is a StyledDocument.  If the associated document
0188             * is not a StyledDocument, the associated components font
0189             * is used.  If there is no associated component, null 
0190             * is returned.
0191             */
0192            public Font getFont() {
0193                Document doc = getDocument();
0194                if (doc instanceof  StyledDocument) {
0195                    AttributeSet attr = getAttributes();
0196                    return ((StyledDocument) doc).getFont(attr);
0197                }
0198                Component c = getContainer();
0199                if (c != null) {
0200                    return c.getFont();
0201                }
0202                return null;
0203            }
0204
0205            /**
0206             * Determine if the glyphs should be underlined.  If true,
0207             * an underline should be drawn through the baseline.
0208             */
0209            public boolean isUnderline() {
0210                AttributeSet attr = getAttributes();
0211                return StyleConstants.isUnderline(attr);
0212            }
0213
0214            /**
0215             * Determine if the glyphs should have a strikethrough
0216             * line.  If true, a line should be drawn through the center
0217             * of the glyphs.
0218             */
0219            public boolean isStrikeThrough() {
0220                AttributeSet attr = getAttributes();
0221                return StyleConstants.isStrikeThrough(attr);
0222            }
0223
0224            /**
0225             * Determine if the glyphs should be rendered as superscript.
0226             */
0227            public boolean isSubscript() {
0228                AttributeSet attr = getAttributes();
0229                return StyleConstants.isSubscript(attr);
0230            }
0231
0232            /**
0233             * Determine if the glyphs should be rendered as subscript.
0234             */
0235            public boolean isSuperscript() {
0236                AttributeSet attr = getAttributes();
0237                return StyleConstants.isSuperscript(attr);
0238            }
0239
0240            /**
0241             * Fetch the TabExpander to use if tabs are present in this view.
0242             */
0243            public TabExpander getTabExpander() {
0244                return expander;
0245            }
0246
0247            /**
0248             * Check to see that a glyph painter exists.  If a painter
0249             * doesn't exist, a default glyph painter will be installed.  
0250             */
0251            protected void checkPainter() {
0252                if (painter == null) {
0253                    if (defaultPainter == null) {
0254                        // the classname should probably come from a property file.
0255                        String classname = "javax.swing.text.GlyphPainter1";
0256                        try {
0257                            Class c;
0258                            ClassLoader loader = getClass().getClassLoader();
0259                            if (loader != null) {
0260                                c = loader.loadClass(classname);
0261                            } else {
0262                                c = Class.forName(classname);
0263                            }
0264                            Object o = c.newInstance();
0265                            if (o instanceof  GlyphPainter) {
0266                                defaultPainter = (GlyphPainter) o;
0267                            }
0268                        } catch (Throwable e) {
0269                            throw new StateInvariantError(
0270                                    "GlyphView: Can't load glyph painter: "
0271                                            + classname);
0272                        }
0273                    }
0274                    setGlyphPainter(defaultPainter.getPainter(this ,
0275                            getStartOffset(), getEndOffset()));
0276                }
0277            }
0278
0279            // --- TabableView methods --------------------------------------
0280
0281            /**
0282             * Determines the desired span when using the given 
0283             * tab expansion implementation.  
0284             *
0285             * @param x the position the view would be located
0286             *  at for the purpose of tab expansion >= 0.
0287             * @param e how to expand the tabs when encountered.
0288             * @return the desired span >= 0
0289             * @see TabableView#getTabbedSpan
0290             */
0291            public float getTabbedSpan(float x, TabExpander e) {
0292                checkPainter();
0293
0294                TabExpander old = expander;
0295                expander = e;
0296
0297                if (expander != old) {
0298                    // setting expander can change horizontal span of the view,
0299                    // so we have to call preferenceChanged()
0300                    preferenceChanged(null, true, false);
0301                }
0302
0303                this .x = (int) x;
0304                int p0 = getStartOffset();
0305                int p1 = getEndOffset();
0306                float width = painter.getSpan(this , p0, p1, expander, x);
0307                return width;
0308            }
0309
0310            /**
0311             * Determines the span along the same axis as tab 
0312             * expansion for a portion of the view.  This is
0313             * intended for use by the TabExpander for cases
0314             * where the tab expansion involves aligning the
0315             * portion of text that doesn't have whitespace 
0316             * relative to the tab stop.  There is therefore
0317             * an assumption that the range given does not
0318             * contain tabs.
0319             * <p>
0320             * This method can be called while servicing the
0321             * getTabbedSpan or getPreferredSize.  It has to
0322             * arrange for its own text buffer to make the
0323             * measurements.
0324             *
0325             * @param p0 the starting document offset >= 0
0326             * @param p1 the ending document offset >= p0
0327             * @return the span >= 0
0328             */
0329            public float getPartialSpan(int p0, int p1) {
0330                checkPainter();
0331                float width = painter.getSpan(this , p0, p1, expander, x);
0332                return width;
0333            }
0334
0335            // --- View methods ---------------------------------------------
0336
0337            /**
0338             * Fetches the portion of the model that this view is responsible for.
0339             *
0340             * @return the starting offset into the model
0341             * @see View#getStartOffset
0342             */
0343            public int getStartOffset() {
0344                Element e = getElement();
0345                return (length > 0) ? e.getStartOffset() + offset : e
0346                        .getStartOffset();
0347            }
0348
0349            /**
0350             * Fetches the portion of the model that this view is responsible for.
0351             *
0352             * @return the ending offset into the model
0353             * @see View#getEndOffset
0354             */
0355            public int getEndOffset() {
0356                Element e = getElement();
0357                return (length > 0) ? e.getStartOffset() + offset + length : e
0358                        .getEndOffset();
0359            }
0360
0361            /**
0362             * Lazily initializes the selections field
0363             */
0364            private void initSelections(int p0, int p1) {
0365                int viewPosCount = p1 - p0 + 1;
0366                if (selections == null || viewPosCount > selections.length) {
0367                    selections = new byte[viewPosCount];
0368                    return;
0369                }
0370                for (int i = 0; i < viewPosCount; selections[i++] = 0)
0371                    ;
0372            }
0373
0374            /**
0375             * Renders a portion of a text style run.
0376             *
0377             * @param g the rendering surface to use
0378             * @param a the allocated region to render into
0379             */
0380            public void paint(Graphics g, Shape a) {
0381                checkPainter();
0382
0383                boolean paintedText = false;
0384                Component c = getContainer();
0385                int p0 = getStartOffset();
0386                int p1 = getEndOffset();
0387                Rectangle alloc = (a instanceof  Rectangle) ? (Rectangle) a : a
0388                        .getBounds();
0389                Color bg = getBackground();
0390                Color fg = getForeground();
0391
0392                if (c instanceof  JTextComponent) {
0393                    JTextComponent tc = (JTextComponent) c;
0394                    if (!tc.isEnabled()) {
0395                        fg = tc.getDisabledTextColor();
0396                    }
0397                }
0398                if (bg != null) {
0399                    g.setColor(bg);
0400                    g.fillRect(alloc.x, alloc.y, alloc.width, alloc.height);
0401                }
0402                if (c instanceof  JTextComponent) {
0403                    JTextComponent tc = (JTextComponent) c;
0404                    Highlighter h = tc.getHighlighter();
0405                    if (h instanceof  LayeredHighlighter) {
0406                        ((LayeredHighlighter) h).paintLayeredHighlights(g, p0,
0407                                p1, a, tc, this );
0408                    }
0409                }
0410
0411                if (Utilities.isComposedTextElement(getElement())) {
0412                    Utilities.paintComposedText(g, a.getBounds(), this );
0413                    paintedText = true;
0414                } else if (c instanceof  JTextComponent) {
0415                    JTextComponent tc = (JTextComponent) c;
0416                    Color selFG = tc.getSelectedTextColor();
0417
0418                    if (// there's a highlighter (bug 4532590), and
0419                    (tc.getHighlighter() != null) &&
0420                    // selected text color is different from regular foreground
0421                            (selFG != null) && !selFG.equals(fg)) {
0422
0423                        Highlighter.Highlight[] h = tc.getHighlighter()
0424                                .getHighlights();
0425                        if (h.length != 0) {
0426                            boolean initialized = false;
0427                            int viewSelectionCount = 0;
0428                            for (int i = 0; i < h.length; i++) {
0429                                Highlighter.Highlight highlight = h[i];
0430                                int hStart = highlight.getStartOffset();
0431                                int hEnd = highlight.getEndOffset();
0432                                if (hStart > p1 || hEnd < p0) {
0433                                    // the selection is out of this view 
0434                                    continue;
0435                                }
0436                                if (!SwingUtilities2.useSelectedTextColor(
0437                                        highlight, tc)) {
0438                                    continue;
0439                                }
0440                                if (hStart <= p0 && hEnd >= p1) {
0441                                    // the whole view is selected 
0442                                    paintTextUsingColor(g, a, selFG, p0, p1);
0443                                    paintedText = true;
0444                                    break;
0445                                }
0446                                // the array is lazily created only when the view 
0447                                // is partially selected 
0448                                if (!initialized) {
0449                                    initSelections(p0, p1);
0450                                    initialized = true;
0451                                }
0452                                hStart = Math.max(p0, hStart);
0453                                hEnd = Math.min(p1, hEnd);
0454                                paintTextUsingColor(g, a, selFG, hStart, hEnd);
0455                                // the array represents view positions [0, p1-p0+1] 
0456                                // later will iterate this array and sum its 
0457                                // elements. Positions with sum == 0 are not selected. 
0458                                selections[hStart - p0]++;
0459                                selections[hEnd - p0]--;
0460
0461                                viewSelectionCount++;
0462                            }
0463
0464                            if (!paintedText && viewSelectionCount > 0) {
0465                                // the view is partially selected 
0466                                int curPos = -1;
0467                                int startPos = 0;
0468                                int viewLen = p1 - p0;
0469                                while (curPos++ < viewLen) {
0470                                    // searching for the next selection start 
0471                                    while (curPos < viewLen
0472                                            && selections[curPos] == 0)
0473                                        curPos++;
0474                                    if (startPos != curPos) {
0475                                        // paint unselected text 
0476                                        paintTextUsingColor(g, a, fg, p0
0477                                                + startPos, p0 + curPos);
0478                                    }
0479                                    int checkSum = 0;
0480                                    // searching for next start position of unselected text 
0481                                    while (curPos < viewLen
0482                                            && (checkSum += selections[curPos]) != 0)
0483                                        curPos++;
0484                                    startPos = curPos;
0485                                }
0486                                paintedText = true;
0487                            }
0488                        }
0489                    }
0490                }
0491                if (!paintedText)
0492                    paintTextUsingColor(g, a, fg, p0, p1);
0493            }
0494
0495            /**
0496             * Paints the specified region of text in the specified color. 
0497             */
0498            final void paintTextUsingColor(Graphics g, Shape a, Color c,
0499                    int p0, int p1) {
0500                // render the glyphs
0501                g.setColor(c);
0502                painter.paint(this , g, a, p0, p1);
0503
0504                // render underline or strikethrough if set.
0505                boolean underline = isUnderline();
0506                boolean strike = isStrikeThrough();
0507                if (underline || strike) {
0508                    // calculate x coordinates
0509                    Rectangle alloc = (a instanceof  Rectangle) ? (Rectangle) a
0510                            : a.getBounds();
0511                    View parent = getParent();
0512                    if ((parent != null) && (parent.getEndOffset() == p1)) {
0513                        // strip whitespace on end
0514                        Segment s = getText(p0, p1);
0515                        while (Character.isWhitespace(s.last())) {
0516                            p1 -= 1;
0517                            s.count -= 1;
0518                        }
0519                        SegmentCache.releaseSharedSegment(s);
0520                    }
0521                    int x0 = alloc.x;
0522                    int p = getStartOffset();
0523                    if (p != p0) {
0524                        x0 += (int) painter.getSpan(this , p, p0,
0525                                getTabExpander(), x0);
0526                    }
0527                    int x1 = x0
0528                            + (int) painter.getSpan(this , p0, p1,
0529                                    getTabExpander(), x0);
0530
0531                    // calculate y coordinate
0532                    int y = alloc.y + alloc.height
0533                            - (int) painter.getDescent(this );
0534                    if (underline) {
0535                        int yTmp = y + 1;
0536                        g.drawLine(x0, yTmp, x1, yTmp);
0537                    }
0538                    if (strike) {
0539                        // move y coordinate above baseline
0540                        int yTmp = y - (int) (painter.getAscent(this ) * 0.3f);
0541                        g.drawLine(x0, yTmp, x1, yTmp);
0542                    }
0543
0544                }
0545            }
0546
0547            /**
0548             * Determines the preferred span for this view along an
0549             * axis. 
0550             *
0551             * @param axis may be either View.X_AXIS or View.Y_AXIS
0552             * @return   the span the view would like to be rendered into >= 0.
0553             *           Typically the view is told to render into the span
0554             *           that is returned, although there is no guarantee.  
0555             *           The parent may choose to resize or break the view.
0556             */
0557            public float getPreferredSpan(int axis) {
0558                if (impliedCR) {
0559                    return 0;
0560                }
0561                checkPainter();
0562                int p0 = getStartOffset();
0563                int p1 = getEndOffset();
0564                switch (axis) {
0565                case View.X_AXIS:
0566                    if (skipWidth) {
0567                        return 0;
0568                    }
0569                    return painter.getSpan(this , p0, p1, expander, this .x);
0570                case View.Y_AXIS:
0571                    float h = painter.getHeight(this );
0572                    if (isSuperscript()) {
0573                        h += h / 3;
0574                    }
0575                    return h;
0576                default:
0577                    throw new IllegalArgumentException("Invalid axis: " + axis);
0578                }
0579            }
0580
0581            /**
0582             * Determines the desired alignment for this view along an
0583             * axis.  For the label, the alignment is along the font
0584             * baseline for the y axis, and the superclasses alignment
0585             * along the x axis.
0586             *
0587             * @param axis may be either View.X_AXIS or View.Y_AXIS
0588             * @return the desired alignment.  This should be a value
0589             *   between 0.0 and 1.0 inclusive, where 0 indicates alignment at the
0590             *   origin and 1.0 indicates alignment to the full span
0591             *   away from the origin.  An alignment of 0.5 would be the
0592             *   center of the view.
0593             */
0594            public float getAlignment(int axis) {
0595                checkPainter();
0596                if (axis == View.Y_AXIS) {
0597                    boolean sup = isSuperscript();
0598                    boolean sub = isSubscript();
0599                    float h = painter.getHeight(this );
0600                    float d = painter.getDescent(this );
0601                    float a = painter.getAscent(this );
0602                    float align;
0603                    if (sup) {
0604                        align = 1.0f;
0605                    } else if (sub) {
0606                        align = (h > 0) ? (h - (d + (a / 2))) / h : 0;
0607                    } else {
0608                        align = (h > 0) ? (h - d) / h : 0;
0609                    }
0610                    return align;
0611                }
0612                return super .getAlignment(axis);
0613            }
0614
0615            /**
0616             * Provides a mapping from the document model coordinate space
0617             * to the coordinate space of the view mapped to it.
0618             *
0619             * @param pos the position to convert >= 0
0620             * @param a   the allocated region to render into
0621             * @param b   either <code>Position.Bias.Forward</code>
0622             *                or <code>Position.Bias.Backward</code>
0623             * @return the bounding box of the given position
0624             * @exception BadLocationException  if the given position does not represent a
0625             *   valid location in the associated document
0626             * @see View#modelToView
0627             */
0628            public Shape modelToView(int pos, Shape a, Position.Bias b)
0629                    throws BadLocationException {
0630                checkPainter();
0631                return painter.modelToView(this , pos, b, a);
0632            }
0633
0634            /**
0635             * Provides a mapping from the view coordinate space to the logical
0636             * coordinate space of the model.
0637             *
0638             * @param x the X coordinate >= 0
0639             * @param y the Y coordinate >= 0
0640             * @param a the allocated region to render into
0641             * @param biasReturn either <code>Position.Bias.Forward</code>
0642             *  or <code>Position.Bias.Backward</code> is returned as the
0643             *  zero-th element of this array
0644             * @return the location within the model that best represents the
0645             *  given point of view >= 0
0646             * @see View#viewToModel
0647             */
0648            public int viewToModel(float x, float y, Shape a,
0649                    Position.Bias[] biasReturn) {
0650                checkPainter();
0651                return painter.viewToModel(this , x, y, a, biasReturn);
0652            }
0653
0654            /**
0655             * Determines how attractive a break opportunity in 
0656             * this view is.  This can be used for determining which
0657             * view is the most attractive to call <code>breakView</code>
0658             * on in the process of formatting.  The
0659             * higher the weight, the more attractive the break.  A
0660             * value equal to or lower than <code>View.BadBreakWeight</code>
0661             * should not be considered for a break.  A value greater
0662             * than or equal to <code>View.ForcedBreakWeight</code> should
0663             * be broken.
0664             * <p>
0665             * This is implemented to forward to the superclass for 
0666             * the Y_AXIS.  Along the X_AXIS the following values
0667             * may be returned.
0668             * <dl>
0669             * <dt><b>View.ExcellentBreakWeight</b>
0670             * <dd>if there is whitespace proceeding the desired break 
0671             *   location.  
0672             * <dt><b>View.BadBreakWeight</b>
0673             * <dd>if the desired break location results in a break
0674             *   location of the starting offset.
0675             * <dt><b>View.GoodBreakWeight</b>
0676             * <dd>if the other conditions don't occur.
0677             * </dl>
0678             * This will normally result in the behavior of breaking
0679             * on a whitespace location if one can be found, otherwise
0680             * breaking between characters.
0681             *
0682             * @param axis may be either View.X_AXIS or View.Y_AXIS
0683             * @param pos the potential location of the start of the 
0684             *   broken view >= 0.  This may be useful for calculating tab
0685             *   positions.
0686             * @param len specifies the relative length from <em>pos</em>
0687             *   where a potential break is desired >= 0.
0688             * @return the weight, which should be a value between
0689             *   View.ForcedBreakWeight and View.BadBreakWeight.
0690             * @see LabelView
0691             * @see ParagraphView
0692             * @see View#BadBreakWeight
0693             * @see View#GoodBreakWeight
0694             * @see View#ExcellentBreakWeight
0695             * @see View#ForcedBreakWeight
0696             */
0697            public int getBreakWeight(int axis, float pos, float len) {
0698                if (axis == View.X_AXIS) {
0699                    checkPainter();
0700                    int p0 = getStartOffset();
0701                    int p1 = painter.getBoundedPosition(this , p0, pos, len);
0702                    if (p1 == p0) {
0703                        // can't even fit a single character
0704                        return View.BadBreakWeight;
0705                    }
0706                    if (getBreakSpot(p0, p1) != -1) {
0707                        return View.ExcellentBreakWeight;
0708                    }
0709                    // Nothing good to break on.
0710                    // breaking on the View boundary is better than splitting it
0711                    if (p1 == getEndOffset()) {
0712                        return View.GoodBreakWeight;
0713                    } else {
0714                        return View.GoodBreakWeight - 1;
0715                    }
0716                }
0717                return super .getBreakWeight(axis, pos, len);
0718            }
0719
0720            /**
0721             * Breaks this view on the given axis at the given length.
0722             * This is implemented to attempt to break on a whitespace
0723             * location, and returns a fragment with the whitespace at
0724             * the end.  If a whitespace location can't be found, the
0725             * nearest character is used.
0726             *
0727             * @param axis may be either View.X_AXIS or View.Y_AXIS
0728             * @param p0 the location in the model where the
0729             *  fragment should start it's representation >= 0.
0730             * @param pos the position along the axis that the
0731             *  broken view would occupy >= 0.  This may be useful for
0732             *  things like tab calculations.
0733             * @param len specifies the distance along the axis
0734             *  where a potential break is desired >= 0.  
0735             * @return the fragment of the view that represents the
0736             *  given span, if the view can be broken.  If the view
0737             *  doesn't support breaking behavior, the view itself is
0738             *  returned.
0739             * @see View#breakView
0740             */
0741            public View breakView(int axis, int p0, float pos, float len) {
0742                if (axis == View.X_AXIS) {
0743                    checkPainter();
0744                    int p1 = painter.getBoundedPosition(this , p0, pos, len);
0745                    int breakSpot = getBreakSpot(p0, p1);
0746
0747                    if (breakSpot != -1) {
0748                        p1 = breakSpot;
0749                    }
0750                    // else, no break in the region, return a fragment of the
0751                    // bounded region.
0752                    if (p0 == getStartOffset() && p1 == getEndOffset()) {
0753                        return this ;
0754                    }
0755                    GlyphView v = (GlyphView) createFragment(p0, p1);
0756                    v.x = (int) pos;
0757                    return v;
0758                }
0759                return this ;
0760            }
0761
0762            /**
0763             * Returns a location to break at in the passed in region, or -1 if
0764             * there isn't a good location to break at in the specified region.
0765             */
0766            private int getBreakSpot(int p0, int p1) {
0767                Document doc = getDocument();
0768
0769                if (doc != null
0770                        && Boolean.TRUE
0771                                .equals(doc
0772                                        .getProperty(AbstractDocument.MultiByteProperty))) {
0773                    return getBreakSpotUseBreakIterator(p0, p1);
0774                }
0775                return getBreakSpotUseWhitespace(p0, p1);
0776            }
0777
0778            /**
0779             * Returns the appropriate place to break based on the last whitespace
0780             * character encountered.
0781             */
0782            private int getBreakSpotUseWhitespace(int p0, int p1) {
0783                Segment s = getText(p0, p1);
0784
0785                for (char ch = s.last(); ch != Segment.DONE; ch = s.previous()) {
0786                    if (Character.isWhitespace(ch)) {
0787                        // found whitespace
0788                        SegmentCache.releaseSharedSegment(s);
0789                        return s.getIndex() - s.getBeginIndex() + 1 + p0;
0790                    }
0791                }
0792                SegmentCache.releaseSharedSegment(s);
0793                return -1;
0794            }
0795
0796            /**
0797             * Returns the appropriate place to break based on BreakIterator.
0798             */
0799            private int getBreakSpotUseBreakIterator(int p0, int p1) {
0800                // Certain regions require context for BreakIterator, start from
0801                // our parents start offset.
0802                Element parent = getElement().getParentElement();
0803                int parent0;
0804                int parent1;
0805                Container c = getContainer();
0806                BreakIterator breaker;
0807
0808                if (parent == null) {
0809                    parent0 = p0;
0810                    parent1 = p1;
0811                } else {
0812                    parent0 = parent.getStartOffset();
0813                    parent1 = parent.getEndOffset();
0814                }
0815                if (c != null) {
0816                    breaker = BreakIterator.getLineInstance(c.getLocale());
0817                } else {
0818                    breaker = BreakIterator.getLineInstance();
0819                }
0820
0821                Segment s = getText(parent0, parent1);
0822                int breakPoint;
0823
0824                // Needed to initialize the Segment.
0825                s.first();
0826                breaker.setText(s);
0827
0828                if (p1 == parent1) {
0829                    // This will most likely return the end, the assumption is
0830                    // that if parent1 == p1, then we are the last portion of
0831                    // a paragraph
0832                    breakPoint = breaker.last();
0833                } else if (p1 + 1 == parent1) {
0834                    // assert(s.count > 1)
0835                    breakPoint = breaker.following(s.offset + s.count - 2);
0836                    if (breakPoint >= s.count + s.offset) {
0837                        breakPoint = breaker.preceding(s.offset + s.count - 1);
0838                    }
0839                } else {
0840                    breakPoint = breaker.preceding(p1 - parent0 + s.offset + 1);
0841                }
0842
0843                int retValue = -1;
0844
0845                if (breakPoint != BreakIterator.DONE) {
0846                    breakPoint = breakPoint - s.offset + parent0;
0847                    if (breakPoint > p0) {
0848                        if (p0 == parent0 && breakPoint == p0) {
0849                            retValue = -1;
0850                        } else if (breakPoint <= p1) {
0851                            retValue = breakPoint;
0852                        }
0853                    }
0854                }
0855                SegmentCache.releaseSharedSegment(s);
0856                return retValue;
0857            }
0858
0859            /**
0860             * Creates a view that represents a portion of the element.
0861             * This is potentially useful during formatting operations
0862             * for taking measurements of fragments of the view.  If 
0863             * the view doesn't support fragmenting (the default), it 
0864             * should return itself.  
0865             * <p>
0866             * This view does support fragmenting.  It is implemented
0867             * to return a nested class that shares state in this view 
0868             * representing only a portion of the view.
0869             *
0870             * @param p0 the starting offset >= 0.  This should be a value
0871             *   greater or equal to the element starting offset and
0872             *   less than the element ending offset.
0873             * @param p1 the ending offset > p0.  This should be a value
0874             *   less than or equal to the elements end offset and
0875             *   greater than the elements starting offset.
0876             * @return the view fragment, or itself if the view doesn't
0877             *   support breaking into fragments
0878             * @see LabelView
0879             */
0880            public View createFragment(int p0, int p1) {
0881                checkPainter();
0882                Element elem = getElement();
0883                GlyphView v = (GlyphView) clone();
0884                v.offset = p0 - elem.getStartOffset();
0885                v.length = p1 - p0;
0886                v.painter = painter.getPainter(v, p0, p1);
0887                v.justificationInfo = null;
0888                return v;
0889            }
0890
0891            /**
0892             * Provides a way to determine the next visually represented model
0893             * location that one might place a caret.  Some views may not be
0894             * visible, they might not be in the same order found in the model, or
0895             * they just might not allow access to some of the locations in the
0896             * model.
0897             *
0898             * @param pos the position to convert >= 0
0899             * @param a the allocated region to render into
0900             * @param direction the direction from the current position that can
0901             *  be thought of as the arrow keys typically found on a keyboard.
0902             *  This may be SwingConstants.WEST, SwingConstants.EAST, 
0903             *  SwingConstants.NORTH, or SwingConstants.SOUTH.  
0904             * @return the location within the model that best represents the next
0905             *  location visual position.
0906             * @exception BadLocationException
0907             * @exception IllegalArgumentException for an invalid direction
0908             */
0909            public int getNextVisualPositionFrom(int pos, Position.Bias b,
0910                    Shape a, int direction, Position.Bias[] biasRet)
0911                    throws BadLocationException {
0912
0913                return painter.getNextVisualPositionFrom(this , pos, b, a,
0914                        direction, biasRet);
0915            }
0916
0917            /**
0918             * Gives notification that something was inserted into 
0919             * the document in a location that this view is responsible for.  
0920             * This is implemented to call preferenceChanged along the
0921             * axis the glyphs are rendered.
0922             *
0923             * @param e the change information from the associated document
0924             * @param a the current allocation of the view
0925             * @param f the factory to use to rebuild if the view has children
0926             * @see View#insertUpdate
0927             */
0928            public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
0929                justificationInfo = null;
0930                syncCR();
0931                preferenceChanged(null, true, false);
0932            }
0933
0934            /**
0935             * Gives notification that something was removed from the document
0936             * in a location that this view is responsible for.
0937             * This is implemented to call preferenceChanged along the
0938             * axis the glyphs are rendered.
0939             *
0940             * @param e the change information from the associated document
0941             * @param a the current allocation of the view
0942             * @param f the factory to use to rebuild if the view has children
0943             * @see View#removeUpdate
0944             */
0945            public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
0946                justificationInfo = null;
0947                syncCR();
0948                preferenceChanged(null, true, false);
0949            }
0950
0951            /**
0952             * Gives notification from the document that attributes were changed
0953             * in a location that this view is responsible for.
0954             * This is implemented to call preferenceChanged along both the
0955             * horizontal and vertical axis.
0956             *
0957             * @param e the change information from the associated document
0958             * @param a the current allocation of the view
0959             * @param f the factory to use to rebuild if the view has children
0960             * @see View#changedUpdate
0961             */
0962            public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
0963                syncCR();
0964                preferenceChanged(null, true, true);
0965            }
0966
0967            // checks if the paragraph is empty and updates impliedCR flag 
0968            // accordingly
0969            private void syncCR() {
0970                if (impliedCR) {
0971                    Element parent = getElement().getParentElement();
0972                    impliedCR = (parent != null && parent.getElementCount() > 1);
0973                }
0974            }
0975
0976            /**
0977             * Class to hold data needed to justify this GlyphView in a PargraphView.Row
0978             */
0979            static class JustificationInfo {
0980                //justifiable content start
0981                final int start;
0982                //justifiable content end
0983                final int end;
0984                final int leadingSpaces;
0985                final int contentSpaces;
0986                final int trailingSpaces;
0987                final boolean hasTab;
0988                final BitSet spaceMap;
0989
0990                JustificationInfo(int start, int end, int leadingSpaces,
0991                        int contentSpaces, int trailingSpaces, boolean hasTab,
0992                        BitSet spaceMap) {
0993                    this .start = start;
0994                    this .end = end;
0995                    this .leadingSpaces = leadingSpaces;
0996                    this .contentSpaces = contentSpaces;
0997                    this .trailingSpaces = trailingSpaces;
0998                    this .hasTab = hasTab;
0999                    this .spaceMap = spaceMap;
1000                }
1001            }
1002
1003            JustificationInfo getJustificationInfo(int rowStartOffset) {
1004                if (justificationInfo != null) {
1005                    return justificationInfo;
1006                }
1007                //states for the parsing
1008                final int TRAILING = 0;
1009                final int CONTENT = 1;
1010                final int SPACES = 2;
1011                int startOffset = getStartOffset();
1012                int endOffset = getEndOffset();
1013                Segment segment = getText(startOffset, endOffset);
1014                int txtOffset = segment.offset;
1015                int txtEnd = segment.offset + segment.count - 1;
1016                int startContentPosition = txtEnd + 1;
1017                int endContentPosition = txtOffset - 1;
1018                int lastTabPosition = txtOffset - 1;
1019                int trailingSpaces = 0;
1020                int contentSpaces = 0;
1021                int leadingSpaces = 0;
1022                boolean hasTab = false;
1023                BitSet spaceMap = new BitSet(endOffset - startOffset + 1);
1024
1025                //we parse conent to the right of the rightmost TAB only.
1026                //we are looking for the trailing and leading spaces.
1027                //position after the leading spaces (startContentPosition)
1028                //position before the trailing spaces (endContentPosition)
1029                for (int i = txtEnd, state = TRAILING; i >= txtOffset; i--) {
1030                    if (' ' == segment.array[i]) {
1031                        spaceMap.set(i - txtOffset);
1032                        if (state == TRAILING) {
1033                            trailingSpaces++;
1034                        } else if (state == CONTENT) {
1035                            state = SPACES;
1036                            leadingSpaces = 1;
1037                        } else if (state == SPACES) {
1038                            leadingSpaces++;
1039                        }
1040                    } else if ('\t' == segment.array[i]) {
1041                        hasTab = true;
1042                        break;
1043                    } else {
1044                        if (state == TRAILING) {
1045                            if ('\n' != segment.array[i]
1046                                    && '\r' != segment.array[i]) {
1047                                state = CONTENT;
1048                                endContentPosition = i;
1049                            }
1050                        } else if (state == CONTENT) {
1051                            //do nothing
1052                        } else if (state == SPACES) {
1053                            contentSpaces += leadingSpaces;
1054                            leadingSpaces = 0;
1055                        }
1056                        startContentPosition = i;
1057                    }
1058                }
1059
1060                SegmentCache.releaseSharedSegment(segment);
1061
1062                int startJustifiableContent = -1;
1063                if (startContentPosition < txtEnd) {
1064                    startJustifiableContent = startContentPosition - txtOffset;
1065                }
1066                int endJustifiableContent = -1;
1067                if (endContentPosition > txtOffset) {
1068                    endJustifiableContent = endContentPosition - txtOffset;
1069                }
1070                justificationInfo = new JustificationInfo(
1071                        startJustifiableContent, endJustifiableContent,
1072                        leadingSpaces, contentSpaces, trailingSpaces, hasTab,
1073                        spaceMap);
1074                return justificationInfo;
1075            }
1076
1077            // --- variables ------------------------------------------------
1078
1079            /**
1080             * Used by paint() to store highlighted view positions
1081             */
1082            private byte[] selections = null;
1083
1084            int offset;
1085            int length;
1086            // if it is an implied newline character
1087            boolean impliedCR;
1088            private static final String IMPLIED_CR = "CR";
1089            boolean skipWidth;
1090
1091            /**
1092             * how to expand tabs
1093             */
1094            TabExpander expander;
1095
1096            /**
1097             * location for determining tab expansion against.
1098             */
1099            int x;
1100
1101            /**
1102             * Glyph rendering functionality.
1103             */
1104            GlyphPainter painter;
1105
1106            /**
1107             * The prototype painter used by default.
1108             */
1109            static GlyphPainter defaultPainter;
1110
1111            private JustificationInfo justificationInfo = null;
1112
1113            /**
1114             * A class to perform rendering of the glyphs.
1115             * This can be implemented to be stateless, or
1116             * to hold some information as a cache to 
1117             * facilitate faster rendering and model/view
1118             * translation.  At a minimum, the GlyphPainter
1119             * allows a View implementation to perform its
1120             * duties independant of a particular version
1121             * of JVM and selection of capabilities (i.e.
1122             * shaping for i18n, etc).
1123             *
1124             * @since 1.3
1125             */
1126            public static abstract class GlyphPainter {
1127
1128                /**
1129                 * Determine the span the glyphs given a start location
1130                 * (for tab expansion).
1131                 */
1132                public abstract float getSpan(GlyphView v, int p0, int p1,
1133                        TabExpander e, float x);
1134
1135                public abstract float getHeight(GlyphView v);
1136
1137                public abstract float getAscent(GlyphView v);
1138
1139                public abstract float getDescent(GlyphView v);
1140
1141                /**
1142                 * Paint the glyphs representing the given range.
1143                 */
1144                public abstract void paint(GlyphView v, Graphics g, Shape a,
1145                        int p0, int p1);
1146
1147                /**
1148                 * Provides a mapping from the document model coordinate space
1149                 * to the coordinate space of the view mapped to it.
1150                 * This is shared by the broken views.
1151                 *
1152                 * @param v     the <code>GlyphView</code> containing the 
1153                 *              destination coordinate space
1154                 * @param pos   the position to convert
1155                 * @param bias  either <code>Position.Bias.Forward</code>
1156                 *                  or <code>Position.Bias.Backward</code>
1157                 * @param a     Bounds of the View
1158                 * @return      the bounding box of the given position
1159                 * @exception BadLocationException  if the given position does not represent a
1160                 *   valid location in the associated document
1161                 * @see View#modelToView
1162                 */
1163                public abstract Shape modelToView(GlyphView v, int pos,
1164                        Position.Bias bias, Shape a)
1165                        throws BadLocationException;
1166
1167                /**
1168                 * Provides a mapping from the view coordinate space to the logical
1169                 * coordinate space of the model.
1170                 *
1171                 * @param v          the <code>GlyphView</code> to provide a mapping for
1172                 * @param x          the X coordinate
1173                 * @param y          the Y coordinate
1174                 * @param a          the allocated region to render into
1175                 * @param biasReturn either <code>Position.Bias.Forward</code>
1176                 *                   or <code>Position.Bias.Backward</code> 
1177                 *                   is returned as the zero-th element of this array
1178                 * @return the location within the model that best represents the
1179                 *         given point of view
1180                 * @see View#viewToModel
1181                 */
1182                public abstract int viewToModel(GlyphView v, float x, float y,
1183                        Shape a, Position.Bias[] biasReturn);
1184
1185                /**
1186                 * Determines the model location that represents the
1187                 * maximum advance that fits within the given span.
1188                 * This could be used to break the given view.  The result 
1189                 * should be a location just shy of the given advance.  This
1190                 * differs from viewToModel which returns the closest
1191                 * position which might be proud of the maximum advance.
1192                 *
1193                 * @param v the view to find the model location to break at.
1194                 * @param p0 the location in the model where the
1195                 *  fragment should start it's representation >= 0.
1196                 * @param x  the graphic location along the axis that the
1197                 *  broken view would occupy >= 0.  This may be useful for
1198                 *  things like tab calculations.
1199                 * @param len specifies the distance into the view
1200                 *  where a potential break is desired >= 0.  
1201                 * @return the maximum model location possible for a break.
1202                 * @see View#breakView
1203                 */
1204                public abstract int getBoundedPosition(GlyphView v, int p0,
1205                        float x, float len);
1206
1207                /**
1208                 * Create a painter to use for the given GlyphView.  If 
1209                 * the painter carries state it can create another painter
1210                 * to represent a new GlyphView that is being created.  If
1211                 * the painter doesn't hold any significant state, it can
1212                 * return itself.  The default behavior is to return itself.
1213                 * @param v  the <code>GlyphView</code> to provide a painter for
1214                 * @param p0 the starting document offset >= 0
1215                 * @param p1 the ending document offset >= p0
1216                 */
1217                public GlyphPainter getPainter(GlyphView v, int p0, int p1) {
1218                    return this ;
1219                }
1220
1221                /**
1222                 * Provides a way to determine the next visually represented model
1223                 * location that one might place a caret.  Some views may not be
1224                 * visible, they might not be in the same order found in the model, or
1225                 * they just might not allow access to some of the locations in the
1226                 * model.
1227                 *
1228                 * @param v the view to use
1229                 * @param pos the position to convert >= 0
1230                 * @param b   either <code>Position.Bias.Forward</code>
1231                 *                or <code>Position.Bias.Backward</code>
1232                 * @param a the allocated region to render into
1233                 * @param direction the direction from the current position that can
1234                 *  be thought of as the arrow keys typically found on a keyboard.
1235                 *  This may be SwingConstants.WEST, SwingConstants.EAST, 
1236                 *  SwingConstants.NORTH, or SwingConstants.SOUTH.  
1237                 * @param biasRet  either <code>Position.Bias.Forward</code>
1238                 *                 or <code>Position.Bias.Backward</code> 
1239                 *                 is returned as the zero-th element of this array
1240                 * @return the location within the model that best represents the next
1241                 *  location visual position.
1242                 * @exception BadLocationException
1243                 * @exception IllegalArgumentException for an invalid direction
1244                 */
1245                public int getNextVisualPositionFrom(GlyphView v, int pos,
1246                        Position.Bias b, Shape a, int direction,
1247                        Position.Bias[] biasRet) throws BadLocationException {
1248
1249                    int startOffset = v.getStartOffset();
1250                    int endOffset = v.getEndOffset();
1251                    Segment text;
1252
1253                    switch (direction) {
1254                    case View.NORTH:
1255                    case View.SOUTH:
1256                        if (pos != -1) {
1257                            // Presumably pos is between startOffset and endOffset,
1258                            // since GlyphView is only one line, we won't contain
1259                            // the position to the nort/south, therefore return -1.
1260                            return -1;
1261                        }
1262                        Container container = v.getContainer();
1263
1264                        if (container instanceof  JTextComponent) {
1265                            Caret c = ((JTextComponent) container).getCaret();
1266                            Point magicPoint;
1267                            magicPoint = (c != null) ? c
1268                                    .getMagicCaretPosition() : null;
1269
1270                            if (magicPoint == null) {
1271                                biasRet[0] = Position.Bias.Forward;
1272                                return startOffset;
1273                            }
1274                            int value = v.viewToModel(magicPoint.x, 0f, a,
1275                                    biasRet);
1276                            return value;
1277                        }
1278                        break;
1279                    case View.EAST:
1280                        if (startOffset == v.getDocument().getLength()) {
1281                            if (pos == -1) {
1282                                biasRet[0] = Position.Bias.Forward;
1283                                return startOffset;
1284                            }
1285                            // End case for bidi text where newline is at beginning
1286                            // of line.
1287                            return -1;
1288                        }
1289                        if (pos == -1) {
1290                            biasRet[0] = Position.Bias.Forward;
1291                            return startOffset;
1292                        }
1293                        if (pos == endOffset) {
1294                            return -1;
1295                        }
1296                        if (++pos == endOffset) {
1297                            // Assumed not used in bidi text, GlyphPainter2 will
1298                            // override as necessary, therefore return -1.
1299                            return -1;
1300                        } else {
1301                            biasRet[0] = Position.Bias.Forward;
1302                        }
1303                        return pos;
1304                    case View.WEST:
1305                        if (startOffset == v.getDocument().getLength()) {
1306                            if (pos == -1) {
1307                                biasRet[0] = Position.Bias.Forward;
1308                                return startOffset;
1309                            }
1310                            // End case for bidi text where newline is at beginning
1311                            // of line.
1312                            return -1;
1313                        }
1314                        if (pos == -1) {
1315                            // Assumed not used in bidi text, GlyphPainter2 will
1316                            // override as necessary, therefore return -1.
1317                            biasRet[0] = Position.Bias.Forward;
1318                            return endOffset - 1;
1319                        }
1320                        if (pos == startOffset) {
1321                            return -1;
1322                        }
1323                        biasRet[0] = Position.Bias.Forward;
1324                        return (pos - 1);
1325                    default:
1326                        throw new IllegalArgumentException("Bad direction: "
1327                                + direction);
1328                    }
1329                    return pos;
1330
1331                }
1332            }
1333        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.