Source Code Cross Referenced for ParagraphView.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 1997-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.util.Arrays;
0028        import java.awt.*;
0029        import java.awt.font.TextAttribute;
0030        import javax.swing.event.*;
0031        import javax.swing.SizeRequirements;
0032
0033        /**
0034         * View of a simple line-wrapping paragraph that supports
0035         * multiple fonts, colors, components, icons, etc.  It is
0036         * basically a vertical box with a margin around it.  The 
0037         * contents of the box are a bunch of rows which are special 
0038         * horizontal boxes.  This view creates a collection of
0039         * views that represent the child elements of the paragraph 
0040         * element.  Each of these views are placed into a row 
0041         * directly if they will fit, otherwise the <code>breakView</code>
0042         * method is called to try and carve the view into pieces
0043         * that fit.
0044         *
0045         * @author  Timothy Prinzing
0046         * @author  Scott Violet
0047         * @author  Igor Kushnirskiy
0048         * @version 1.103 05/05/07
0049         * @see     View
0050         */
0051        public class ParagraphView extends FlowView implements  TabExpander {
0052
0053            /**
0054             * Constructs a <code>ParagraphView</code> for the given element.
0055             *
0056             * @param elem the element that this view is responsible for
0057             */
0058            public ParagraphView(Element elem) {
0059                super (elem, View.Y_AXIS);
0060                setPropertiesFromAttributes();
0061                Document doc = elem.getDocument();
0062                Object i18nFlag = doc
0063                        .getProperty(AbstractDocument.I18NProperty);
0064                if ((i18nFlag != null) && i18nFlag.equals(Boolean.TRUE)) {
0065                    try {
0066                        if (i18nStrategy == null) {
0067                            // the classname should probably come from a property file.
0068                            String classname = "javax.swing.text.TextLayoutStrategy";
0069                            ClassLoader loader = getClass().getClassLoader();
0070                            if (loader != null) {
0071                                i18nStrategy = loader.loadClass(classname);
0072                            } else {
0073                                i18nStrategy = Class.forName(classname);
0074                            }
0075                        }
0076                        Object o = i18nStrategy.newInstance();
0077                        if (o instanceof  FlowStrategy) {
0078                            strategy = (FlowStrategy) o;
0079                        }
0080                    } catch (Throwable e) {
0081                        throw new StateInvariantError(
0082                                "ParagraphView: Can't create i18n strategy: "
0083                                        + e.getMessage());
0084                    }
0085                }
0086            }
0087
0088            /**
0089             * Sets the type of justification.
0090             *
0091             * @param j one of the following values:
0092             * <ul>
0093             * <li><code>StyleConstants.ALIGN_LEFT</code>
0094             * <li><code>StyleConstants.ALIGN_CENTER</code>
0095             * <li><code>StyleConstants.ALIGN_RIGHT</code>
0096             * </ul>
0097             */
0098            protected void setJustification(int j) {
0099                justification = j;
0100            }
0101
0102            /**
0103             * Sets the line spacing.
0104             *
0105             * @param ls the value is a factor of the line hight
0106             */
0107            protected void setLineSpacing(float ls) {
0108                lineSpacing = ls;
0109            }
0110
0111            /**
0112             * Sets the indent on the first line.
0113             *
0114             * @param fi the value in points
0115             */
0116            protected void setFirstLineIndent(float fi) {
0117                firstLineIndent = (int) fi;
0118            }
0119
0120            /**
0121             * Set the cached properties from the attributes.
0122             */
0123            protected void setPropertiesFromAttributes() {
0124                AttributeSet attr = getAttributes();
0125                if (attr != null) {
0126                    setParagraphInsets(attr);
0127                    Integer a = (Integer) attr
0128                            .getAttribute(StyleConstants.Alignment);
0129                    int alignment;
0130                    if (a == null) {
0131                        Document doc = getElement().getDocument();
0132                        Object o = doc.getProperty(TextAttribute.RUN_DIRECTION);
0133                        if ((o != null)
0134                                && o.equals(TextAttribute.RUN_DIRECTION_RTL)) {
0135                            alignment = StyleConstants.ALIGN_RIGHT;
0136                        } else {
0137                            alignment = StyleConstants.ALIGN_LEFT;
0138                        }
0139                    } else {
0140                        alignment = a.intValue();
0141                    }
0142                    setJustification(alignment);
0143                    setLineSpacing(StyleConstants.getLineSpacing(attr));
0144                    setFirstLineIndent(StyleConstants.getFirstLineIndent(attr));
0145                }
0146            }
0147
0148            /**
0149             * Returns the number of views that this view is
0150             * responsible for.
0151             * The child views of the paragraph are rows which
0152             * have been used to arrange pieces of the <code>View</code>s
0153             * that represent the child elements.  This is the number 
0154             * of views that have been tiled in two dimensions,
0155             * and should be equivalent to the number of child elements
0156             * to the element this view is responsible for.
0157             *
0158             * @return the number of views that this <code>ParagraphView</code>
0159             *		is responsible for
0160             */
0161            protected int getLayoutViewCount() {
0162                return layoutPool.getViewCount();
0163            }
0164
0165            /**
0166             * Returns the view at a given <code>index</code>.
0167             * The child views of the paragraph are rows which
0168             * have been used to arrange pieces of the <code>Views</code>
0169             * that represent the child elements.  This methods returns
0170             * the view responsible for the child element index
0171             * (prior to breaking).  These are the Views that were
0172             * produced from a factory (to represent the child
0173             * elements) and used for layout.
0174             *
0175             * @param index the <code>index</code> of the desired view
0176             * @return the view at <code>index</code>
0177             */
0178            protected View getLayoutView(int index) {
0179                return layoutPool.getView(index);
0180            }
0181
0182            /**
0183             * Adjusts the given row if possible to fit within the
0184             * layout span.  By default this will try to find the 
0185             * highest break weight possible nearest the end of
0186             * the row.  If a forced break is encountered, the
0187             * break will be positioned there.
0188             * <p>
0189             * This is meant for internal usage, and should not be used directly.
0190             * 
0191             * @param r the row to adjust to the current layout
0192             *  	span
0193             * @param desiredSpan the current layout span >= 0
0194             * @param x the location r starts at
0195             */
0196            protected void adjustRow(Row r, int desiredSpan, int x) {
0197            }
0198
0199            /**
0200             * Returns the next visual position for the cursor, in 
0201             * either the east or west direction.
0202             * Overridden from <code>CompositeView</code>.
0203             * @param pos position into the model
0204             * @param b either <code>Position.Bias.Forward</code> or
0205             *          <code>Position.Bias.Backward</code>
0206             * @param a the allocated region to render into
0207             * @param direction either <code>SwingConstants.NORTH</code>
0208             *		or <code>SwingConstants.SOUTH</code>
0209             * @param biasRet an array containing the bias that were checked
0210             *	in this method
0211             * @return the location in the model that represents the
0212             *	next location visual position
0213             */
0214            protected int getNextNorthSouthVisualPositionFrom(int pos,
0215                    Position.Bias b, Shape a, int direction,
0216                    Position.Bias[] biasRet) throws BadLocationException {
0217                int vIndex;
0218                if (pos == -1) {
0219                    vIndex = (direction == NORTH) ? getViewCount() - 1 : 0;
0220                } else {
0221                    if (b == Position.Bias.Backward && pos > 0) {
0222                        vIndex = getViewIndexAtPosition(pos - 1);
0223                    } else {
0224                        vIndex = getViewIndexAtPosition(pos);
0225                    }
0226                    if (direction == NORTH) {
0227                        if (vIndex == 0) {
0228                            return -1;
0229                        }
0230                        vIndex--;
0231                    } else if (++vIndex >= getViewCount()) {
0232                        return -1;
0233                    }
0234                }
0235                // vIndex gives index of row to look in.
0236                JTextComponent text = (JTextComponent) getContainer();
0237                Caret c = text.getCaret();
0238                Point magicPoint;
0239                magicPoint = (c != null) ? c.getMagicCaretPosition() : null;
0240                int x;
0241                if (magicPoint == null) {
0242                    Shape posBounds;
0243                    try {
0244                        posBounds = text.getUI().modelToView(text, pos, b);
0245                    } catch (BadLocationException exc) {
0246                        posBounds = null;
0247                    }
0248                    if (posBounds == null) {
0249                        x = 0;
0250                    } else {
0251                        x = posBounds.getBounds().x;
0252                    }
0253                } else {
0254                    x = magicPoint.x;
0255                }
0256                return getClosestPositionTo(pos, b, a, direction, biasRet,
0257                        vIndex, x);
0258            }
0259
0260            /**
0261             * Returns the closest model position to <code>x</code>.
0262             * <code>rowIndex</code> gives the index of the view that corresponds
0263             * that should be looked in.
0264             * @param pos  position into the model
0265             * @param a the allocated region to render into
0266             * @param direction one of the following values:
0267             * <ul>
0268             * <li><code>SwingConstants.NORTH</code>
0269             * <li><code>SwingConstants.SOUTH</code>
0270             * </ul>
0271             * @param biasRet an array containing the bias that were checked
0272             *	in this method
0273             * @param rowIndex the index of the view
0274             * @param x the x coordinate of interest
0275             * @return the closest model position to <code>x</code>
0276             */
0277            // NOTE: This will not properly work if ParagraphView contains
0278            // other ParagraphViews. It won't raise, but this does not message
0279            // the children views with getNextVisualPositionFrom.
0280            protected int getClosestPositionTo(int pos, Position.Bias b,
0281                    Shape a, int direction, Position.Bias[] biasRet,
0282                    int rowIndex, int x) throws BadLocationException {
0283                JTextComponent text = (JTextComponent) getContainer();
0284                Document doc = getDocument();
0285                AbstractDocument aDoc = (doc instanceof  AbstractDocument) ? (AbstractDocument) doc
0286                        : null;
0287                View row = getView(rowIndex);
0288                int lastPos = -1;
0289                // This could be made better to check backward positions too.
0290                biasRet[0] = Position.Bias.Forward;
0291                for (int vc = 0, numViews = row.getViewCount(); vc < numViews; vc++) {
0292                    View v = row.getView(vc);
0293                    int start = v.getStartOffset();
0294                    boolean ltr = (aDoc != null) ? aDoc.isLeftToRight(start,
0295                            start + 1) : true;
0296                    if (ltr) {
0297                        lastPos = start;
0298                        for (int end = v.getEndOffset(); lastPos < end; lastPos++) {
0299                            float xx = text.modelToView(lastPos).getBounds().x;
0300                            if (xx >= x) {
0301                                while (++lastPos < end
0302                                        && text.modelToView(lastPos)
0303                                                .getBounds().x == xx) {
0304                                }
0305                                return --lastPos;
0306                            }
0307                        }
0308                        lastPos--;
0309                    } else {
0310                        for (lastPos = v.getEndOffset() - 1; lastPos >= start; lastPos--) {
0311                            float xx = text.modelToView(lastPos).getBounds().x;
0312                            if (xx >= x) {
0313                                while (--lastPos >= start
0314                                        && text.modelToView(lastPos)
0315                                                .getBounds().x == xx) {
0316                                }
0317                                return ++lastPos;
0318                            }
0319                        }
0320                        lastPos++;
0321                    }
0322                }
0323                if (lastPos == -1) {
0324                    return getStartOffset();
0325                }
0326                return lastPos;
0327            }
0328
0329            /**
0330             * Determines in which direction the next view lays.
0331             * Consider the <code>View</code> at index n.
0332             * Typically the <code>View</code>s are layed out
0333             * from left to right, so that the <code>View</code>
0334             * to the EAST will be at index n + 1, and the
0335             * <code>View</code> to the WEST will be at index n - 1.
0336             * In certain situations, such as with bidirectional text,
0337             * it is possible that the <code>View</code> to EAST is not
0338             * at index n + 1, but rather at index n - 1,
0339             * or that the <code>View</code> to the WEST is not at
0340             * index n - 1, but index n + 1.  In this case this method
0341             * would return true, indicating the <code>View</code>s are
0342             * layed out in descending order.
0343             * <p>
0344             * This will return true if the text is layed out right
0345             * to left at position, otherwise false.
0346             *
0347             * @param position position into the model
0348             * @param bias either <code>Position.Bias.Forward</code> or
0349             *          <code>Position.Bias.Backward</code>
0350             * @return true if the text is layed out right to left at
0351             *         position, otherwise false.
0352             */
0353            protected boolean flipEastAndWestAtEnds(int position,
0354                    Position.Bias bias) {
0355                Document doc = getDocument();
0356                if (doc instanceof  AbstractDocument
0357                        && !((AbstractDocument) doc).isLeftToRight(
0358                                getStartOffset(), getStartOffset() + 1)) {
0359                    return true;
0360                }
0361                return false;
0362            }
0363
0364            // --- FlowView methods ---------------------------------------------
0365
0366            /**
0367             * Fetches the constraining span to flow against for
0368             * the given child index.
0369             * @param index the index of the view being queried
0370             * @return the constraining span for the given view at
0371             *	<code>index</code>
0372             * @since 1.3
0373             */
0374            public int getFlowSpan(int index) {
0375                View child = getView(index);
0376                int adjust = 0;
0377                if (child instanceof  Row) {
0378                    Row row = (Row) child;
0379                    adjust = row.getLeftInset() + row.getRightInset();
0380                }
0381                return (layoutSpan == Integer.MAX_VALUE) ? layoutSpan
0382                        : (layoutSpan - adjust);
0383            }
0384
0385            /**
0386             * Fetches the location along the flow axis that the
0387             * flow span will start at.
0388             * @param index the index of the view being queried
0389             * @return the location for the given view at
0390             *	<code>index</code>
0391             * @since 1.3
0392             */
0393            public int getFlowStart(int index) {
0394                View child = getView(index);
0395                int adjust = 0;
0396                if (child instanceof  Row) {
0397                    Row row = (Row) child;
0398                    adjust = row.getLeftInset();
0399                }
0400                return tabBase + adjust;
0401            }
0402
0403            /**
0404             * Create a <code>View</code> that should be used to hold a 
0405             * a row's worth of children in a flow.
0406             * @return the new <code>View</code>
0407             * @since 1.3
0408             */
0409            protected View createRow() {
0410                return new Row(getElement());
0411            }
0412
0413            // --- TabExpander methods ------------------------------------------
0414
0415            /**
0416             * Returns the next tab stop position given a reference position.
0417             * This view implements the tab coordinate system, and calls
0418             * <code>getTabbedSpan</code> on the logical children in the process 
0419             * of layout to determine the desired span of the children.  The
0420             * logical children can delegate their tab expansion upward to
0421             * the paragraph which knows how to expand tabs. 
0422             * <code>LabelView</code> is an example of a view that delegates
0423             * its tab expansion needs upward to the paragraph.
0424             * <p>
0425             * This is implemented to try and locate a <code>TabSet</code>
0426             * in the paragraph element's attribute set.  If one can be
0427             * found, its settings will be used, otherwise a default expansion
0428             * will be provided.  The base location for for tab expansion
0429             * is the left inset from the paragraphs most recent allocation
0430             * (which is what the layout of the children is based upon).
0431             *
0432             * @param x the X reference position
0433             * @param tabOffset the position within the text stream
0434             *   that the tab occurred at >= 0
0435             * @return the trailing end of the tab expansion >= 0
0436             * @see TabSet
0437             * @see TabStop
0438             * @see LabelView
0439             */
0440            public float nextTabStop(float x, int tabOffset) {
0441                // If the text isn't left justified, offset by 10 pixels!
0442                if (justification != StyleConstants.ALIGN_LEFT)
0443                    return x + 10.0f;
0444                x -= tabBase;
0445                TabSet tabs = getTabSet();
0446                if (tabs == null) {
0447                    // a tab every 72 pixels.
0448                    return (float) (tabBase + (((int) x / 72 + 1) * 72));
0449                }
0450                TabStop tab = tabs.getTabAfter(x + .01f);
0451                if (tab == null) {
0452                    // no tab, do a default of 5 pixels.
0453                    // Should this cause a wrapping of the line?
0454                    return tabBase + x + 5.0f;
0455                }
0456                int alignment = tab.getAlignment();
0457                int offset;
0458                switch (alignment) {
0459                default:
0460                case TabStop.ALIGN_LEFT:
0461                    // Simple case, left tab.
0462                    return tabBase + tab.getPosition();
0463                case TabStop.ALIGN_BAR:
0464                    // PENDING: what does this mean?
0465                    return tabBase + tab.getPosition();
0466                case TabStop.ALIGN_RIGHT:
0467                case TabStop.ALIGN_CENTER:
0468                    offset = findOffsetToCharactersInString(tabChars,
0469                            tabOffset + 1);
0470                    break;
0471                case TabStop.ALIGN_DECIMAL:
0472                    offset = findOffsetToCharactersInString(tabDecimalChars,
0473                            tabOffset + 1);
0474                    break;
0475                }
0476                if (offset == -1) {
0477                    offset = getEndOffset();
0478                }
0479                float charsSize = getPartialSize(tabOffset + 1, offset);
0480                switch (alignment) {
0481                case TabStop.ALIGN_RIGHT:
0482                case TabStop.ALIGN_DECIMAL:
0483                    // right and decimal are treated the same way, the new
0484                    // position will be the location of the tab less the
0485                    // partialSize.
0486                    return tabBase + Math.max(x, tab.getPosition() - charsSize);
0487                case TabStop.ALIGN_CENTER:
0488                    // Similar to right, but half the partialSize.
0489                    return tabBase
0490                            + Math.max(x, tab.getPosition() - charsSize / 2.0f);
0491                }
0492                // will never get here!
0493                return x;
0494            }
0495
0496            /**
0497             * Gets the <code>Tabset</code> to be used in calculating tabs.
0498             *
0499             * @return the <code>TabSet</code>
0500             */
0501            protected TabSet getTabSet() {
0502                return StyleConstants.getTabSet(getElement().getAttributes());
0503            }
0504
0505            /**
0506             * Returns the size used by the views between
0507             * <code>startOffset</code> and <code>endOffset</code>.
0508             * This uses <code>getPartialView</code> to calculate the
0509             * size if the child view implements the 
0510             * <code>TabableView</code> interface. If a 
0511             * size is needed and a <code>View</code> does not implement
0512             * the <code>TabableView</code> interface,
0513             * the <code>preferredSpan</code> will be used.
0514             *
0515             * @param startOffset the starting document offset >= 0
0516             * @param endOffset the ending document offset >= startOffset
0517             * @return the size >= 0
0518             */
0519            protected float getPartialSize(int startOffset, int endOffset) {
0520                float size = 0.0f;
0521                int viewIndex;
0522                int numViews = getViewCount();
0523                View view;
0524                int viewEnd;
0525                int tempEnd;
0526
0527                // Have to search layoutPool!
0528                // PENDING: when ParagraphView supports breaking location
0529                // into layoutPool will have to change!
0530                viewIndex = getElement().getElementIndex(startOffset);
0531                numViews = layoutPool.getViewCount();
0532                while (startOffset < endOffset && viewIndex < numViews) {
0533                    view = layoutPool.getView(viewIndex++);
0534                    viewEnd = view.getEndOffset();
0535                    tempEnd = Math.min(endOffset, viewEnd);
0536                    if (view instanceof  TabableView)
0537                        size += ((TabableView) view).getPartialSpan(
0538                                startOffset, tempEnd);
0539                    else if (startOffset == view.getStartOffset()
0540                            && tempEnd == view.getEndOffset())
0541                        size += view.getPreferredSpan(View.X_AXIS);
0542                    else
0543                        // PENDING: should we handle this better?
0544                        return 0.0f;
0545                    startOffset = viewEnd;
0546                }
0547                return size;
0548            }
0549
0550            /**
0551             * Finds the next character in the document with a character in
0552             * <code>string</code>, starting at offset <code>start</code>. If
0553             * there are no characters found, -1 will be returned.
0554             *
0555             * @param string the string of characters
0556             * @param start where to start in the model >= 0
0557             * @return the document offset, or -1 if no characters found
0558             */
0559            protected int findOffsetToCharactersInString(char[] string,
0560                    int start) {
0561                int stringLength = string.length;
0562                int end = getEndOffset();
0563                Segment seg = new Segment();
0564                try {
0565                    getDocument().getText(start, end - start, seg);
0566                } catch (BadLocationException ble) {
0567                    return -1;
0568                }
0569                for (int counter = seg.offset, maxCounter = seg.offset
0570                        + seg.count; counter < maxCounter; counter++) {
0571                    char currentChar = seg.array[counter];
0572                    for (int subCounter = 0; subCounter < stringLength; subCounter++) {
0573                        if (currentChar == string[subCounter])
0574                            return counter - seg.offset + start;
0575                    }
0576                }
0577                // No match.
0578                return -1;
0579            }
0580
0581            /**
0582             * Returns where the tabs are calculated from.
0583             * @return where tabs are calculated from
0584             */
0585            protected float getTabBase() {
0586                return (float) tabBase;
0587            }
0588
0589            // ---- View methods ----------------------------------------------------
0590
0591            /**
0592             * Renders using the given rendering surface and area on that
0593             * surface.  This is implemented to delgate to the superclass
0594             * after stashing the base coordinate for tab calculations.
0595             *
0596             * @param g the rendering surface to use
0597             * @param a the allocated region to render into
0598             * @see View#paint
0599             */
0600            public void paint(Graphics g, Shape a) {
0601                Rectangle alloc = (a instanceof  Rectangle) ? (Rectangle) a : a
0602                        .getBounds();
0603                tabBase = alloc.x + getLeftInset();
0604                super .paint(g, a);
0605
0606                // line with the negative firstLineIndent value needs
0607                // special handling
0608                if (firstLineIndent < 0) {
0609                    Shape sh = getChildAllocation(0, a);
0610                    if ((sh != null) && sh.intersects(alloc)) {
0611                        int x = alloc.x + getLeftInset() + firstLineIndent;
0612                        int y = alloc.y + getTopInset();
0613
0614                        Rectangle clip = g.getClipBounds();
0615                        tempRect.x = x + getOffset(X_AXIS, 0);
0616                        tempRect.y = y + getOffset(Y_AXIS, 0);
0617                        tempRect.width = getSpan(X_AXIS, 0) - firstLineIndent;
0618                        tempRect.height = getSpan(Y_AXIS, 0);
0619                        if (tempRect.intersects(clip)) {
0620                            tempRect.x = tempRect.x - firstLineIndent;
0621                            paintChild(g, tempRect, 0);
0622                        }
0623                    }
0624                }
0625            }
0626
0627            /**
0628             * Determines the desired alignment for this view along an
0629             * axis.  This is implemented to give the alignment to the
0630             * center of the first row along the y axis, and the default
0631             * along the x axis.
0632             *
0633             * @param axis may be either <code>View.X_AXIS</code> or
0634             *	 <code>View.Y_AXIS</code>
0635             * @return the desired alignment.  This should be a value
0636             *   between 0.0 and 1.0 inclusive, where 0 indicates alignment at the
0637             *   origin and 1.0 indicates alignment to the full span
0638             *   away from the origin.  An alignment of 0.5 would be the
0639             *   center of the view.
0640             */
0641            public float getAlignment(int axis) {
0642                switch (axis) {
0643                case Y_AXIS:
0644                    float a = 0.5f;
0645                    if (getViewCount() != 0) {
0646                        int paragraphSpan = (int) getPreferredSpan(View.Y_AXIS);
0647                        View v = getView(0);
0648                        int rowSpan = (int) v.getPreferredSpan(View.Y_AXIS);
0649                        a = (paragraphSpan != 0) ? ((float) (rowSpan / 2))
0650                                / paragraphSpan : 0;
0651                    }
0652                    return a;
0653                case X_AXIS:
0654                    return 0.5f;
0655                default:
0656                    throw new IllegalArgumentException("Invalid axis: " + axis);
0657                }
0658            }
0659
0660            /**
0661             * Breaks this view on the given axis at the given length.
0662             * <p>
0663             * <code>ParagraphView</code> instances are breakable
0664             * along the <code>Y_AXIS</code> only, and only if
0665             * <code>len</code> is after the first line.
0666             *
0667             * @param axis may be either <code>View.X_AXIS</code>
0668             *  or <code>View.Y_AXIS</code>
0669             * @param len specifies where a potential break is desired
0670             *  along the given axis >= 0
0671             * @param a the current allocation of the view
0672             * @return the fragment of the view that represents the
0673             *  given span, if the view can be broken; if the view
0674             *  doesn't support breaking behavior, the view itself is
0675             *  returned
0676             * @see View#breakView
0677             */
0678            public View breakView(int axis, float len, Shape a) {
0679                if (axis == View.Y_AXIS) {
0680                    if (a != null) {
0681                        Rectangle alloc = a.getBounds();
0682                        setSize(alloc.width, alloc.height);
0683                    }
0684                    // Determine what row to break on.
0685
0686                    // PENDING(prinz) add break support
0687                    return this ;
0688                }
0689                return this ;
0690            }
0691
0692            /**
0693             * Gets the break weight for a given location.
0694             * <p>
0695             * <code>ParagraphView</code> instances are breakable
0696             * along the <code>Y_AXIS</code> only, and only if 
0697             * <code>len</code> is after the first row.  If the length
0698             * is less than one row, a value of <code>BadBreakWeight</code>
0699             * is returned.
0700             *
0701             * @param axis may be either <code>View.X_AXIS</code>
0702             *  or <code>View.Y_AXIS</code>
0703             * @param len specifies where a potential break is desired >= 0
0704             * @return a value indicating the attractiveness of breaking here;
0705             *	either <code>GoodBreakWeight</code> or <code>BadBreakWeight</code>
0706             * @see View#getBreakWeight
0707             */
0708            public int getBreakWeight(int axis, float len) {
0709                if (axis == View.Y_AXIS) {
0710                    // PENDING(prinz) make this return a reasonable value
0711                    // when paragraph breaking support is re-implemented.
0712                    // If less than one row, bad weight value should be 
0713                    // returned.
0714                    //return GoodBreakWeight;
0715                    return BadBreakWeight;
0716                }
0717                return BadBreakWeight;
0718            }
0719
0720            /**
0721             * Gives notification from the document that attributes were changed
0722             * in a location that this view is responsible for.
0723             *
0724             * @param changes the change information from the 
0725             *	associated document
0726             * @param a the current allocation of the view
0727             * @param f the factory to use to rebuild if the view has children
0728             * @see View#changedUpdate
0729             */
0730            public void changedUpdate(DocumentEvent changes, Shape a,
0731                    ViewFactory f) {
0732                // update any property settings stored, and layout should be 
0733                // recomputed 
0734                setPropertiesFromAttributes();
0735                layoutChanged(X_AXIS);
0736                layoutChanged(Y_AXIS);
0737                super .changedUpdate(changes, a, f);
0738            }
0739
0740            // --- variables -----------------------------------------------
0741
0742            private int justification;
0743            private float lineSpacing;
0744            /** Indentation for the first line, from the left inset. */
0745            protected int firstLineIndent = 0;
0746
0747            /**
0748             * Used by the TabExpander functionality to determine
0749             * where to base the tab calculations.  This is basically
0750             * the location of the left side of the paragraph.
0751             */
0752            private int tabBase;
0753
0754            /**
0755             * Used to create an i18n-based layout strategy
0756             */
0757            static Class i18nStrategy;
0758
0759            /** Used for searching for a tab. */
0760            static char[] tabChars;
0761            /** Used for searching for a tab or decimal character. */
0762            static char[] tabDecimalChars;
0763
0764            static {
0765                tabChars = new char[1];
0766                tabChars[0] = '\t';
0767                tabDecimalChars = new char[2];
0768                tabDecimalChars[0] = '\t';
0769                tabDecimalChars[1] = '.';
0770            }
0771
0772            /**
0773             * Internally created view that has the purpose of holding
0774             * the views that represent the children of the paragraph
0775             * that have been arranged in rows.
0776             */
0777            class Row extends BoxView {
0778
0779                Row(Element elem) {
0780                    super (elem, View.X_AXIS);
0781                }
0782
0783                /**
0784                 * This is reimplemented to do nothing since the
0785                 * paragraph fills in the row with its needed
0786                 * children.
0787                 */
0788                protected void loadChildren(ViewFactory f) {
0789                }
0790
0791                /**
0792                 * Fetches the attributes to use when rendering.  This view
0793                 * isn't directly responsible for an element so it returns
0794                 * the outer classes attributes.
0795                 */
0796                public AttributeSet getAttributes() {
0797                    View p = getParent();
0798                    return (p != null) ? p.getAttributes() : null;
0799                }
0800
0801                public float getAlignment(int axis) {
0802                    if (axis == View.X_AXIS) {
0803                        switch (justification) {
0804                        case StyleConstants.ALIGN_LEFT:
0805                            return 0;
0806                        case StyleConstants.ALIGN_RIGHT:
0807                            return 1;
0808                        case StyleConstants.ALIGN_CENTER:
0809                            return 0.5f;
0810                        case StyleConstants.ALIGN_JUSTIFIED:
0811                            float rv = 0.5f;
0812                            //if we can justifiy the content always align to
0813                            //the left.
0814                            if (isJustifiableDocument()) {
0815                                rv = 0f;
0816                            }
0817                            return rv;
0818                        }
0819                    }
0820                    return super .getAlignment(axis);
0821                }
0822
0823                /**
0824                 * Provides a mapping from the document model coordinate space
0825                 * to the coordinate space of the view mapped to it.  This is
0826                 * implemented to let the superclass find the position along 
0827                 * the major axis and the allocation of the row is used 
0828                 * along the minor axis, so that even though the children 
0829                 * are different heights they all get the same caret height.
0830                 *
0831                 * @param pos the position to convert
0832                 * @param a the allocated region to render into
0833                 * @return the bounding box of the given position
0834                 * @exception BadLocationException  if the given position does not represent a
0835                 *   valid location in the associated document
0836                 * @see View#modelToView
0837                 */
0838                public Shape modelToView(int pos, Shape a, Position.Bias b)
0839                        throws BadLocationException {
0840                    Rectangle r = a.getBounds();
0841                    View v = getViewAtPosition(pos, r);
0842                    if ((v != null) && (!v.getElement().isLeaf())) {
0843                        // Don't adjust the height if the view represents a branch.
0844                        return super .modelToView(pos, a, b);
0845                    }
0846                    r = a.getBounds();
0847                    int height = r.height;
0848                    int y = r.y;
0849                    Shape loc = super .modelToView(pos, a, b);
0850                    r = loc.getBounds();
0851                    r.height = height;
0852                    r.y = y;
0853                    return r;
0854                }
0855
0856                /**
0857                 * Range represented by a row in the paragraph is only
0858                 * a subset of the total range of the paragraph element.
0859                 * @see View#getRange
0860                 */
0861                public int getStartOffset() {
0862                    int offs = Integer.MAX_VALUE;
0863                    int n = getViewCount();
0864                    for (int i = 0; i < n; i++) {
0865                        View v = getView(i);
0866                        offs = Math.min(offs, v.getStartOffset());
0867                    }
0868                    return offs;
0869                }
0870
0871                public int getEndOffset() {
0872                    int offs = 0;
0873                    int n = getViewCount();
0874                    for (int i = 0; i < n; i++) {
0875                        View v = getView(i);
0876                        offs = Math.max(offs, v.getEndOffset());
0877                    }
0878                    return offs;
0879                }
0880
0881                /**
0882                 * Perform layout for the minor axis of the box (i.e. the
0883                 * axis orthoginal to the axis that it represents).  The results 
0884                 * of the layout should be placed in the given arrays which represent 
0885                 * the allocations to the children along the minor axis.
0886                 * <p>
0887                 * This is implemented to do a baseline layout of the children
0888                 * by calling BoxView.baselineLayout.
0889                 *
0890                 * @param targetSpan the total span given to the view, which
0891                 *  whould be used to layout the children.
0892                 * @param axis the axis being layed out.
0893                 * @param offsets the offsets from the origin of the view for
0894                 *  each of the child views.  This is a return value and is
0895                 *  filled in by the implementation of this method.
0896                 * @param spans the span of each child view.  This is a return
0897                 *  value and is filled in by the implementation of this method.
0898                 * @return the offset and span for each child view in the
0899                 *  offsets and spans parameters
0900                 */
0901                protected void layoutMinorAxis(int targetSpan, int axis,
0902                        int[] offsets, int[] spans) {
0903                    baselineLayout(targetSpan, axis, offsets, spans);
0904                }
0905
0906                protected SizeRequirements calculateMinorAxisRequirements(
0907                        int axis, SizeRequirements r) {
0908                    return baselineRequirements(axis, r);
0909                }
0910
0911                private boolean isLastRow() {
0912                    View parent;
0913                    return ((parent = getParent()) == null || this  == parent
0914                            .getView(parent.getViewCount() - 1));
0915                }
0916
0917                private boolean isBrokenRow() {
0918                    boolean rv = false;
0919                    int viewsCount = getViewCount();
0920                    if (viewsCount > 0) {
0921                        View lastView = getView(viewsCount - 1);
0922                        if (lastView.getBreakWeight(X_AXIS, 0, 0) >= ForcedBreakWeight) {
0923                            rv = true;
0924                        }
0925                    }
0926                    return rv;
0927                }
0928
0929                private boolean isJustifiableDocument() {
0930                    return (!Boolean.TRUE.equals(getDocument().getProperty(
0931                            AbstractDocument.I18NProperty)));
0932                }
0933
0934                /**
0935                 * Whether we need to justify this {@code Row}.
0936                 * At this time (jdk1.6) we support justification on for non
0937                 * 18n text.
0938                 *
0939                 * @return {@code true} if this {@code Row} should be justified.
0940                 */
0941                private boolean isJustifyEnabled() {
0942                    boolean ret = (justification == StyleConstants.ALIGN_JUSTIFIED);
0943
0944                    //no justification for i18n documents
0945                    ret = ret && isJustifiableDocument();
0946
0947                    //no justification for the last row
0948                    ret = ret && !isLastRow();
0949
0950                    //no justification for the broken rows
0951                    ret = ret && !isBrokenRow();
0952
0953                    return ret;
0954                }
0955
0956                //Calls super method after setting spaceAddon to 0.
0957                //Justification should not affect MajorAxisRequirements
0958                @Override
0959                protected SizeRequirements calculateMajorAxisRequirements(
0960                        int axis, SizeRequirements r) {
0961                    int oldJustficationData[] = justificationData;
0962                    justificationData = null;
0963                    SizeRequirements ret = super 
0964                            .calculateMajorAxisRequirements(axis, r);
0965                    if (isJustifyEnabled()) {
0966                        justificationData = oldJustficationData;
0967                    }
0968                    return ret;
0969                }
0970
0971                @Override
0972                protected void layoutMajorAxis(int targetSpan, int axis,
0973                        int[] offsets, int[] spans) {
0974                    int oldJustficationData[] = justificationData;
0975                    justificationData = null;
0976                    super .layoutMajorAxis(targetSpan, axis, offsets, spans);
0977                    if (!isJustifyEnabled()) {
0978                        return;
0979                    }
0980
0981                    int currentSpan = 0;
0982                    for (int span : spans) {
0983                        currentSpan += span;
0984                    }
0985                    if (currentSpan == targetSpan) {
0986                        //no need to justify
0987                        return;
0988                    }
0989
0990                    // we justify text by enlarging spaces by the {@code spaceAddon}.
0991                    // justification is started to the right of the rightmost TAB.
0992                    // leading and trailing spaces are not extendable.
0993                    //
0994                    // GlyphPainter1 uses 
0995                    // justificationData
0996                    // for all painting and measurement.
0997
0998                    int extendableSpaces = 0;
0999                    int startJustifiableContent = -1;
1000                    int endJustifiableContent = -1;
1001                    int lastLeadingSpaces = 0;
1002
1003                    int rowStartOffset = getStartOffset();
1004                    int rowEndOffset = getEndOffset();
1005                    int spaceMap[] = new int[rowEndOffset - rowStartOffset];
1006                    Arrays.fill(spaceMap, 0);
1007                    for (int i = getViewCount() - 1; i >= 0; i--) {
1008                        View view = getView(i);
1009                        if (view instanceof  GlyphView) {
1010                            GlyphView.JustificationInfo justificationInfo = ((GlyphView) view)
1011                                    .getJustificationInfo(rowStartOffset);
1012                            final int viewStartOffset = view.getStartOffset();
1013                            final int offset = viewStartOffset - rowStartOffset;
1014                            for (int j = 0; j < justificationInfo.spaceMap
1015                                    .length(); j++) {
1016                                if (justificationInfo.spaceMap.get(j)) {
1017                                    spaceMap[j + offset] = 1;
1018                                }
1019                            }
1020                            if (startJustifiableContent > 0) {
1021                                if (justificationInfo.end >= 0) {
1022                                    extendableSpaces += justificationInfo.trailingSpaces;
1023                                } else {
1024                                    lastLeadingSpaces += justificationInfo.trailingSpaces;
1025                                }
1026                            }
1027                            if (justificationInfo.start >= 0) {
1028                                startJustifiableContent = justificationInfo.start
1029                                        + viewStartOffset;
1030                                extendableSpaces += lastLeadingSpaces;
1031                            }
1032                            if (justificationInfo.end >= 0
1033                                    && endJustifiableContent < 0) {
1034                                endJustifiableContent = justificationInfo.end
1035                                        + viewStartOffset;
1036                            }
1037                            extendableSpaces += justificationInfo.contentSpaces;
1038                            lastLeadingSpaces = justificationInfo.leadingSpaces;
1039                            if (justificationInfo.hasTab) {
1040                                break;
1041                            }
1042                        }
1043                    }
1044                    if (extendableSpaces <= 0) {
1045                        //there is nothing we can do to justify
1046                        return;
1047                    }
1048                    int adjustment = (targetSpan - currentSpan);
1049                    int spaceAddon = (extendableSpaces > 0) ? adjustment
1050                            / extendableSpaces : 0;
1051                    int spaceAddonLeftoverEnd = -1;
1052                    for (int i = startJustifiableContent - rowStartOffset, leftover = adjustment
1053                            - spaceAddon * extendableSpaces; leftover > 0; leftover -= spaceMap[i], i++) {
1054                        spaceAddonLeftoverEnd = i;
1055                    }
1056                    if (spaceAddon > 0 || spaceAddonLeftoverEnd >= 0) {
1057                        justificationData = (oldJustficationData != null) ? oldJustficationData
1058                                : new int[END_JUSTIFIABLE + 1];
1059                        justificationData[SPACE_ADDON] = spaceAddon;
1060                        justificationData[SPACE_ADDON_LEFTOVER_END] = spaceAddonLeftoverEnd;
1061                        justificationData[START_JUSTIFIABLE] = startJustifiableContent
1062                                - rowStartOffset;
1063                        justificationData[END_JUSTIFIABLE] = endJustifiableContent
1064                                - rowStartOffset;
1065                        super .layoutMajorAxis(targetSpan, axis, offsets, spans);
1066                    }
1067                }
1068
1069                //for justified row we assume the maximum horizontal span 
1070                //is MAX_VALUE.
1071                @Override
1072                public float getMaximumSpan(int axis) {
1073                    float ret;
1074                    if (View.X_AXIS == axis && isJustifyEnabled()) {
1075                        ret = Float.MAX_VALUE;
1076                    } else {
1077                        ret = super .getMaximumSpan(axis);
1078                    }
1079                    return ret;
1080                }
1081
1082                /**
1083                 * Fetches the child view index representing the given position in
1084                 * the model.
1085                 *
1086                 * @param pos the position >= 0
1087                 * @return  index of the view representing the given position, or 
1088                 *   -1 if no view represents that position
1089                 */
1090                protected int getViewIndexAtPosition(int pos) {
1091                    // This is expensive, but are views are not necessarily layed
1092                    // out in model order.
1093                    if (pos < getStartOffset() || pos >= getEndOffset())
1094                        return -1;
1095                    for (int counter = getViewCount() - 1; counter >= 0; counter--) {
1096                        View v = getView(counter);
1097                        if (pos >= v.getStartOffset() && pos < v.getEndOffset()) {
1098                            return counter;
1099                        }
1100                    }
1101                    return -1;
1102                }
1103
1104                /**
1105                 * Gets the left inset.
1106                 *
1107                 * @return the inset
1108                 */
1109                protected short getLeftInset() {
1110                    View parentView;
1111                    int adjustment = 0;
1112                    if ((parentView = getParent()) != null) { //use firstLineIdent for the first row
1113                        if (this  == parentView.getView(0)) {
1114                            adjustment = firstLineIndent;
1115                        }
1116                    }
1117                    return (short) (super .getLeftInset() + adjustment);
1118                }
1119
1120                protected short getBottomInset() {
1121                    return (short) (super .getBottomInset() + ((minorRequest != null) ? minorRequest.preferred
1122                            : 0)
1123                            * lineSpacing);
1124                }
1125
1126                final static int SPACE_ADDON = 0;
1127                final static int SPACE_ADDON_LEFTOVER_END = 1;
1128                final static int START_JUSTIFIABLE = 2;
1129                //this should be the last index in justificationData
1130                final static int END_JUSTIFIABLE = 3;
1131
1132                int justificationData[] = null;
1133            }
1134
1135        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.