Source Code Cross Referenced for AsyncBoxView.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.util.*;
0028        import java.awt.*;
0029        import javax.swing.SwingUtilities;
0030        import javax.swing.event.DocumentEvent;
0031
0032        /**
0033         * A box that does layout asynchronously.  This
0034         * is useful to keep the GUI event thread moving by
0035         * not doing any layout on it.  The layout is done
0036         * on a granularity of operations on the child views.
0037         * After each child view is accessed for some part
0038         * of layout (a potentially time consuming operation) 
0039         * the remaining tasks can be abandoned or a new higher 
0040         * priority task (i.e. to service a synchronous request 
0041         * or a visible area) can be taken on.
0042         * <p>
0043         * While the child view is being accessed
0044         * a read lock is aquired on the associated document 
0045         * so that the model is stable while being accessed.
0046         *
0047         * @author  Timothy Prinzing
0048         * @version 1.24 05/05/07
0049         * @since   1.3
0050         */
0051        public class AsyncBoxView extends View {
0052
0053            /**
0054             * Construct a box view that does asynchronous layout.
0055             *
0056             * @param elem the element of the model to represent
0057             * @param axis the axis to tile along.  This can be
0058             *  either X_AXIS or Y_AXIS.
0059             */
0060            public AsyncBoxView(Element elem, int axis) {
0061                super (elem);
0062                stats = new ArrayList();
0063                this .axis = axis;
0064                locator = new ChildLocator();
0065                flushTask = new FlushTask();
0066                minorSpan = Short.MAX_VALUE;
0067                estimatedMajorSpan = false;
0068            }
0069
0070            /**
0071             * Fetch the major axis (the axis the children
0072             * are tiled along).  This will have a value of
0073             * either X_AXIS or Y_AXIS.
0074             */
0075            public int getMajorAxis() {
0076                return axis;
0077            }
0078
0079            /**
0080             * Fetch the minor axis (the axis orthoginal 
0081             * to the tiled axis).  This will have a value of
0082             * either X_AXIS or Y_AXIS.
0083             */
0084            public int getMinorAxis() {
0085                return (axis == X_AXIS) ? Y_AXIS : X_AXIS;
0086            }
0087
0088            /**
0089             * Get the top part of the margin around the view.
0090             */
0091            public float getTopInset() {
0092                return topInset;
0093            }
0094
0095            /**
0096             * Set the top part of the margin around the view.
0097             *
0098             * @param i the value of the inset
0099             */
0100            public void setTopInset(float i) {
0101                topInset = i;
0102            }
0103
0104            /**
0105             * Get the bottom part of the margin around the view.
0106             */
0107            public float getBottomInset() {
0108                return bottomInset;
0109            }
0110
0111            /**
0112             * Set the bottom part of the margin around the view.
0113             *
0114             * @param i the value of the inset
0115             */
0116            public void setBottomInset(float i) {
0117                bottomInset = i;
0118            }
0119
0120            /**
0121             * Get the left part of the margin around the view.
0122             */
0123            public float getLeftInset() {
0124                return leftInset;
0125            }
0126
0127            /**
0128             * Set the left part of the margin around the view.
0129             *
0130             * @param i the value of the inset
0131             */
0132            public void setLeftInset(float i) {
0133                leftInset = i;
0134            }
0135
0136            /**
0137             * Get the right part of the margin around the view.
0138             */
0139            public float getRightInset() {
0140                return rightInset;
0141            }
0142
0143            /**
0144             * Set the right part of the margin around the view.
0145             *
0146             * @param i the value of the inset
0147             */
0148            public void setRightInset(float i) {
0149                rightInset = i;
0150            }
0151
0152            /**
0153             * Fetch the span along an axis that is taken up by the insets.
0154             *
0155             * @param axis the axis to determine the total insets along,
0156             *  either X_AXIS or Y_AXIS.
0157             * @since 1.4
0158             */
0159            protected float getInsetSpan(int axis) {
0160                float margin = (axis == X_AXIS) ? getLeftInset()
0161                        + getRightInset() : getTopInset() + getBottomInset();
0162                return margin;
0163            }
0164
0165            /**
0166             * Set the estimatedMajorSpan property that determines if the
0167             * major span should be treated as being estimated.  If this
0168             * property is true, the value of setSize along the major axis 
0169             * will change the requirements along the major axis and incremental 
0170             * changes will be ignored until all of the children have been updated
0171             * (which will cause the property to automatically be set to false).
0172             * If the property is false the value of the majorSpan will be
0173             * considered to be accurate and incremental changes will be
0174             * added into the total as they are calculated.
0175             *
0176             * @since 1.4
0177             */
0178            protected void setEstimatedMajorSpan(boolean isEstimated) {
0179                estimatedMajorSpan = isEstimated;
0180            }
0181
0182            /**
0183             * Is the major span currently estimated?
0184             *
0185             * @since 1.4
0186             */
0187            protected boolean getEstimatedMajorSpan() {
0188                return estimatedMajorSpan;
0189            }
0190
0191            /**
0192             * Fetch the object representing the layout state of
0193             * of the child at the given index.
0194             *
0195             * @param index the child index.  This should be a
0196             *   value >= 0 and < getViewCount().
0197             */
0198            protected ChildState getChildState(int index) {
0199                synchronized (stats) {
0200                    if ((index >= 0) && (index < stats.size())) {
0201                        return (ChildState) stats.get(index);
0202                    }
0203                    return null;
0204                }
0205            }
0206
0207            /**
0208             * Fetch the queue to use for layout.
0209             */
0210            protected LayoutQueue getLayoutQueue() {
0211                return LayoutQueue.getDefaultQueue();
0212            }
0213
0214            /**
0215             * New ChildState records are created through
0216             * this method to allow subclasses the extend
0217             * the ChildState records to do/hold more
0218             */
0219            protected ChildState createChildState(View v) {
0220                return new ChildState(v);
0221            }
0222
0223            /**
0224             * Requirements changed along the major axis.
0225             * This is called by the thread doing layout for 
0226             * the given ChildState object when it has completed
0227             * fetching the child views new preferences.
0228             * Typically this would be the layout thread, but
0229             * might be the event thread if it is trying to update
0230             * something immediately (such as to perform a 
0231             * model/view translation).
0232             * <p>
0233             * This is implemented to mark the major axis as having 
0234             * changed so that a future check to see if the requirements
0235             * need to be published to the parent view will consider
0236             * the major axis.  If the span along the major axis is 
0237             * not estimated, it is updated by the given delta to reflect
0238             * the incremental change.  The delta is ignored if the 
0239             * major span is estimated.
0240             */
0241            protected synchronized void majorRequirementChange(ChildState cs,
0242                    float delta) {
0243                if (estimatedMajorSpan == false) {
0244                    majorSpan += delta;
0245                }
0246                majorChanged = true;
0247            }
0248
0249            /**
0250             * Requirements changed along the minor axis.
0251             * This is called by the thread doing layout for 
0252             * the given ChildState object when it has completed
0253             * fetching the child views new preferences.
0254             * Typically this would be the layout thread, but
0255             * might be the GUI thread if it is trying to update
0256             * something immediately (such as to perform a 
0257             * model/view translation).
0258             */
0259            protected synchronized void minorRequirementChange(ChildState cs) {
0260                minorChanged = true;
0261            }
0262
0263            /**
0264             * Publish the changes in preferences upward to the parent
0265             * view.  This is normally called by the layout thread.
0266             */
0267            protected void flushRequirementChanges() {
0268                AbstractDocument doc = (AbstractDocument) getDocument();
0269                try {
0270                    doc.readLock();
0271
0272                    View parent = null;
0273                    boolean horizontal = false;
0274                    boolean vertical = false;
0275
0276                    synchronized (this ) {
0277                        // perform tasks that iterate over the children while
0278                        // preventing the collection from changing.
0279                        synchronized (stats) {
0280                            int n = getViewCount();
0281                            if ((n > 0) && (minorChanged || estimatedMajorSpan)) {
0282                                LayoutQueue q = getLayoutQueue();
0283                                ChildState min = getChildState(0);
0284                                ChildState pref = getChildState(0);
0285                                float span = 0f;
0286                                for (int i = 1; i < n; i++) {
0287                                    ChildState cs = getChildState(i);
0288                                    if (minorChanged) {
0289                                        if (cs.min > min.min) {
0290                                            min = cs;
0291                                        }
0292                                        if (cs.pref > pref.pref) {
0293                                            pref = cs;
0294                                        }
0295                                    }
0296                                    if (estimatedMajorSpan) {
0297                                        span += cs.getMajorSpan();
0298                                    }
0299                                }
0300
0301                                if (minorChanged) {
0302                                    minRequest = min;
0303                                    prefRequest = pref;
0304                                }
0305                                if (estimatedMajorSpan) {
0306                                    majorSpan = span;
0307                                    estimatedMajorSpan = false;
0308                                    majorChanged = true;
0309                                }
0310                            }
0311                        }
0312
0313                        // message preferenceChanged 
0314                        if (majorChanged || minorChanged) {
0315                            parent = getParent();
0316                            if (parent != null) {
0317                                if (axis == X_AXIS) {
0318                                    horizontal = majorChanged;
0319                                    vertical = minorChanged;
0320                                } else {
0321                                    vertical = majorChanged;
0322                                    horizontal = minorChanged;
0323                                }
0324                            }
0325                            majorChanged = false;
0326                            minorChanged = false;
0327                        }
0328                    }
0329
0330                    // propagate a preferenceChanged, using the
0331                    // layout thread.
0332                    if (parent != null) {
0333                        parent.preferenceChanged(this , horizontal, vertical);
0334
0335                        // probably want to change this to be more exact.
0336                        Component c = getContainer();
0337                        if (c != null) {
0338                            c.repaint();
0339                        }
0340                    }
0341                } finally {
0342                    doc.readUnlock();
0343                }
0344            }
0345
0346            /**
0347             * Calls the superclass to update the child views, and
0348             * updates the status records for the children.  This
0349             * is expected to be called while a write lock is held
0350             * on the model so that interaction with the layout
0351             * thread will not happen (i.e. the layout thread 
0352             * acquires a read lock before doing anything). 
0353             *
0354             * @param offset the starting offset into the child views >= 0
0355             * @param length the number of existing views to replace >= 0
0356             * @param views the child views to insert
0357             */
0358            public void replace(int offset, int length, View[] views) {
0359                synchronized (stats) {
0360                    // remove the replaced state records
0361                    for (int i = 0; i < length; i++) {
0362                        ChildState cs = (ChildState) stats.remove(offset);
0363                        float csSpan = cs.getMajorSpan();
0364
0365                        cs.getChildView().setParent(null);
0366                        if (csSpan != 0) {
0367                            majorRequirementChange(cs, -csSpan);
0368                        }
0369                    }
0370
0371                    // insert the state records for the new children
0372                    LayoutQueue q = getLayoutQueue();
0373                    if (views != null) {
0374                        for (int i = 0; i < views.length; i++) {
0375                            ChildState s = createChildState(views[i]);
0376                            stats.add(offset + i, s);
0377                            q.addTask(s);
0378                        }
0379                    }
0380
0381                    // notify that the size changed
0382                    q.addTask(flushTask);
0383                }
0384            }
0385
0386            /**
0387             * Loads all of the children to initialize the view.
0388             * This is called by the <a href="#setParent">setParent</a> 
0389             * method.  Subclasses can reimplement this to initialize 
0390             * their child views in a different manner.  The default
0391             * implementation creates a child view for each 
0392             * child element.
0393             * <p>
0394             * Normally a write-lock is held on the Document while
0395             * the children are being changed, which keeps the rendering
0396             * and layout threads safe.  The exception to this is when 
0397             * the view is initialized to represent an existing element
0398             * (via this method), so it is synchronized to exclude 
0399             * preferenceChanged while we are initializing.
0400             *
0401             * @param f the view factory
0402             * @see #setParent
0403             */
0404            protected void loadChildren(ViewFactory f) {
0405                Element e = getElement();
0406                int n = e.getElementCount();
0407                if (n > 0) {
0408                    View[] added = new View[n];
0409                    for (int i = 0; i < n; i++) {
0410                        added[i] = f.create(e.getElement(i));
0411                    }
0412                    replace(0, 0, added);
0413                }
0414            }
0415
0416            /**
0417             * Fetches the child view index representing the given position in
0418             * the model.  This is implemented to fetch the view in the case
0419             * where there is a child view for each child element.
0420             *
0421             * @param pos the position >= 0
0422             * @return  index of the view representing the given position, or 
0423             *   -1 if no view represents that position
0424             */
0425            protected synchronized int getViewIndexAtPosition(int pos,
0426                    Position.Bias b) {
0427                boolean isBackward = (b == Position.Bias.Backward);
0428                pos = (isBackward) ? Math.max(0, pos - 1) : pos;
0429                Element elem = getElement();
0430                return elem.getElementIndex(pos);
0431            }
0432
0433            /**
0434             * Update the layout in response to receiving notification of
0435             * change from the model.  This is implemented to note the 
0436             * change on the ChildLocator so that offsets of the children
0437             * will be correctly computed.
0438             *
0439             * @param ec changes to the element this view is responsible
0440             *  for (may be null if there were no changes).
0441             * @param e the change information from the associated document
0442             * @param a the current allocation of the view
0443             * @see #insertUpdate
0444             * @see #removeUpdate
0445             * @see #changedUpdate     
0446             */
0447            protected void updateLayout(DocumentEvent.ElementChange ec,
0448                    DocumentEvent e, Shape a) {
0449                if (ec != null) {
0450                    // the newly inserted children don't have a valid
0451                    // offset so the child locator needs to be messaged
0452                    // that the child prior to the new children has 
0453                    // changed size.
0454                    int index = Math.max(ec.getIndex() - 1, 0);
0455                    ChildState cs = getChildState(index);
0456                    locator.childChanged(cs);
0457                }
0458            }
0459
0460            // --- View methods ------------------------------------
0461
0462            /**
0463             * Sets the parent of the view.
0464             * This is reimplemented to provide the superclass
0465             * behavior as well as calling the <code>loadChildren</code>
0466             * method if this view does not already have children.  
0467             * The children should not be loaded in the 
0468             * constructor because the act of setting the parent
0469             * may cause them to try to search up the hierarchy
0470             * (to get the hosting Container for example).
0471             * If this view has children (the view is being moved
0472             * from one place in the view hierarchy to another), 
0473             * the <code>loadChildren</code> method will not be called.
0474             *
0475             * @param parent the parent of the view, null if none
0476             */
0477            public void setParent(View parent) {
0478                super .setParent(parent);
0479                if ((parent != null) && (getViewCount() == 0)) {
0480                    ViewFactory f = getViewFactory();
0481                    loadChildren(f);
0482                }
0483            }
0484
0485            /**
0486             * Child views can call this on the parent to indicate that
0487             * the preference has changed and should be reconsidered
0488             * for layout.  This is reimplemented to queue new work
0489             * on the layout thread.  This method gets messaged from
0490             * multiple threads via the children.
0491             *
0492             * @param child the child view
0493             * @param width true if the width preference has changed
0494             * @param height true if the height preference has changed
0495             * @see javax.swing.JComponent#revalidate
0496             */
0497            public synchronized void preferenceChanged(View child,
0498                    boolean width, boolean height) {
0499                if (child == null) {
0500                    getParent().preferenceChanged(this , width, height);
0501                } else {
0502                    if (changing != null) {
0503                        View cv = changing.getChildView();
0504                        if (cv == child) {
0505                            // size was being changed on the child, no need to
0506                            // queue work for it.
0507                            changing.preferenceChanged(width, height);
0508                            return;
0509                        }
0510                    }
0511                    int index = getViewIndex(child.getStartOffset(),
0512                            Position.Bias.Forward);
0513                    ChildState cs = getChildState(index);
0514                    cs.preferenceChanged(width, height);
0515                    LayoutQueue q = getLayoutQueue();
0516                    q.addTask(cs);
0517                    q.addTask(flushTask);
0518                }
0519            }
0520
0521            /**
0522             * Sets the size of the view.  This should cause 
0523             * layout of the view if the view caches any layout
0524             * information.
0525             * <p>
0526             * Since the major axis is updated asynchronously and should be 
0527             * the sum of the tiled children the call is ignored for the major 
0528             * axis.  Since the minor axis is flexible, work is queued to resize 
0529             * the children if the minor span changes.
0530             *
0531             * @param width the width >= 0
0532             * @param height the height >= 0
0533             */
0534            public void setSize(float width, float height) {
0535                setSpanOnAxis(X_AXIS, width);
0536                setSpanOnAxis(Y_AXIS, height);
0537            }
0538
0539            /**
0540             * Retrieves the size of the view along an axis.  
0541             *
0542             * @param axis may be either <code>View.X_AXIS</code> or
0543             *		<code>View.Y_AXIS</code>
0544             * @return the current span of the view along the given axis, >= 0
0545             */
0546            float getSpanOnAxis(int axis) {
0547                if (axis == getMajorAxis()) {
0548                    return majorSpan;
0549                }
0550                return minorSpan;
0551            }
0552
0553            /**
0554             * Sets the size of the view along an axis.  Since the major
0555             * axis is updated asynchronously and should be the sum of the
0556             * tiled children the call is ignored for the major axis.  Since
0557             * the minor axis is flexible, work is queued to resize the
0558             * children if the minor span changes.
0559             *
0560             * @param axis may be either <code>View.X_AXIS</code> or
0561             *		<code>View.Y_AXIS</code>
0562             * @param span the span to layout to >= 0
0563             */
0564            void setSpanOnAxis(int axis, float span) {
0565                float margin = getInsetSpan(axis);
0566                if (axis == getMinorAxis()) {
0567                    float targetSpan = span - margin;
0568                    if (targetSpan != minorSpan) {
0569                        minorSpan = targetSpan;
0570
0571                        // mark all of the ChildState instances as needing to
0572                        // resize the child, and queue up work to fix them.
0573                        int n = getViewCount();
0574                        if (n != 0) {
0575                            LayoutQueue q = getLayoutQueue();
0576                            for (int i = 0; i < n; i++) {
0577                                ChildState cs = getChildState(i);
0578                                cs.childSizeValid = false;
0579                                q.addTask(cs);
0580                            }
0581                            q.addTask(flushTask);
0582                        }
0583                    }
0584                } else {
0585                    // along the major axis the value is ignored 
0586                    // unless the estimatedMajorSpan property is
0587                    // true.
0588                    if (estimatedMajorSpan) {
0589                        majorSpan = span - margin;
0590                    }
0591                }
0592            }
0593
0594            /**
0595             * Render the view using the given allocation and
0596             * rendering surface.
0597             * <p>
0598             * This is implemented to determine whether or not the
0599             * desired region to be rendered (i.e. the unclipped 
0600             * area) is up to date or not.  If up-to-date the children
0601             * are rendered.  If not up-to-date, a task to build
0602             * the desired area is placed on the layout queue as
0603             * a high priority task.  This keeps by event thread
0604             * moving by rendering if ready, and postponing until
0605             * a later time if not ready (since paint requests
0606             * can be rescheduled).
0607             *
0608             * @param g the rendering surface to use
0609             * @param alloc the allocated region to render into
0610             * @see View#paint
0611             */
0612            public void paint(Graphics g, Shape alloc) {
0613                synchronized (locator) {
0614                    locator.setAllocation(alloc);
0615                    locator.paintChildren(g);
0616                }
0617            }
0618
0619            /**
0620             * Determines the preferred span for this view along an
0621             * axis.
0622             *
0623             * @param axis may be either View.X_AXIS or View.Y_AXIS
0624             * @return   the span the view would like to be rendered into >= 0.
0625             *           Typically the view is told to render into the span
0626             *           that is returned, although there is no guarantee.  
0627             *           The parent may choose to resize or break the view.
0628             * @exception IllegalArgumentException for an invalid axis type
0629             */
0630            public float getPreferredSpan(int axis) {
0631                float margin = getInsetSpan(axis);
0632                if (axis == this .axis) {
0633                    return majorSpan + margin;
0634                }
0635                if (prefRequest != null) {
0636                    View child = prefRequest.getChildView();
0637                    return child.getPreferredSpan(axis) + margin;
0638                }
0639
0640                // nothing is known about the children yet
0641                return margin + 30;
0642            }
0643
0644            /**
0645             * Determines the minimum span for this view along an
0646             * axis.
0647             *
0648             * @param axis may be either View.X_AXIS or View.Y_AXIS
0649             * @return  the span the view would like to be rendered into >= 0.
0650             *           Typically the view is told to render into the span
0651             *           that is returned, although there is no guarantee.  
0652             *           The parent may choose to resize or break the view.
0653             * @exception IllegalArgumentException for an invalid axis type
0654             */
0655            public float getMinimumSpan(int axis) {
0656                if (axis == this .axis) {
0657                    return getPreferredSpan(axis);
0658                }
0659                if (minRequest != null) {
0660                    View child = minRequest.getChildView();
0661                    return child.getMinimumSpan(axis);
0662                }
0663
0664                // nothing is known about the children yet
0665                if (axis == X_AXIS) {
0666                    return getLeftInset() + getRightInset() + 5;
0667                } else {
0668                    return getTopInset() + getBottomInset() + 5;
0669                }
0670            }
0671
0672            /**
0673             * Determines the maximum span for this view along an
0674             * axis.
0675             *
0676             * @param axis may be either View.X_AXIS or View.Y_AXIS
0677             * @return   the span the view would like to be rendered into >= 0.
0678             *           Typically the view is told to render into the span
0679             *           that is returned, although there is no guarantee.  
0680             *           The parent may choose to resize or break the view.
0681             * @exception IllegalArgumentException for an invalid axis type
0682             */
0683            public float getMaximumSpan(int axis) {
0684                if (axis == this .axis) {
0685                    return getPreferredSpan(axis);
0686                }
0687                return Integer.MAX_VALUE;
0688            }
0689
0690            /** 
0691             * Returns the number of views in this view.  Since
0692             * the default is to not be a composite view this
0693             * returns 0.
0694             *
0695             * @return the number of views >= 0
0696             * @see View#getViewCount
0697             */
0698            public int getViewCount() {
0699                synchronized (stats) {
0700                    return stats.size();
0701                }
0702            }
0703
0704            /** 
0705             * Gets the nth child view.  Since there are no
0706             * children by default, this returns null.
0707             *
0708             * @param n the number of the view to get, >= 0 && < getViewCount()
0709             * @return the view
0710             */
0711            public View getView(int n) {
0712                ChildState cs = getChildState(n);
0713                if (cs != null) {
0714                    return cs.getChildView();
0715                }
0716                return null;
0717            }
0718
0719            /**
0720             * Fetches the allocation for the given child view. 
0721             * This enables finding out where various views
0722             * are located, without assuming the views store
0723             * their location.  This returns null since the
0724             * default is to not have any child views.
0725             *
0726             * @param index the index of the child, >= 0 && < getViewCount()
0727             * @param a  the allocation to this view.
0728             * @return the allocation to the child
0729             */
0730            public Shape getChildAllocation(int index, Shape a) {
0731                Shape ca = locator.getChildAllocation(index, a);
0732                return ca;
0733            }
0734
0735            /**
0736             * Returns the child view index representing the given position in
0737             * the model.  By default a view has no children so this is implemented
0738             * to return -1 to indicate there is no valid child index for any
0739             * position.
0740             *
0741             * @param pos the position >= 0
0742             * @return  index of the view representing the given position, or 
0743             *   -1 if no view represents that position
0744             * @since 1.3
0745             */
0746            public int getViewIndex(int pos, Position.Bias b) {
0747                return getViewIndexAtPosition(pos, b);
0748            }
0749
0750            /**
0751             * Provides a mapping from the document model coordinate space
0752             * to the coordinate space of the view mapped to it.
0753             *
0754             * @param pos the position to convert >= 0
0755             * @param a the allocated region to render into
0756             * @param b the bias toward the previous character or the
0757             *  next character represented by the offset, in case the 
0758             *  position is a boundary of two views. 
0759             * @return the bounding box of the given position is returned
0760             * @exception BadLocationException  if the given position does
0761             *   not represent a valid location in the associated document
0762             * @exception IllegalArgumentException for an invalid bias argument
0763             * @see View#viewToModel
0764             */
0765            public Shape modelToView(int pos, Shape a, Position.Bias b)
0766                    throws BadLocationException {
0767                int index = getViewIndex(pos, b);
0768                Shape ca = locator.getChildAllocation(index, a);
0769
0770                // forward to the child view, and make sure we don't
0771                // interact with the layout thread by synchronizing
0772                // on the child state.
0773                ChildState cs = getChildState(index);
0774                synchronized (cs) {
0775                    View cv = cs.getChildView();
0776                    Shape v = cv.modelToView(pos, ca, b);
0777                    return v;
0778                }
0779            }
0780
0781            /**
0782             * Provides a mapping from the view coordinate space to the logical
0783             * coordinate space of the model.  The biasReturn argument will be
0784             * filled in to indicate that the point given is closer to the next
0785             * character in the model or the previous character in the model.
0786             * <p>
0787             * This is expected to be called by the GUI thread, holding a 
0788             * read-lock on the associated model.  It is implemented to
0789             * locate the child view and determine it's allocation with a
0790             * lock on the ChildLocator object, and to call viewToModel
0791             * on the child view with a lock on the ChildState object 
0792             * to avoid interaction with the layout thread.
0793             *
0794             * @param x the X coordinate >= 0
0795             * @param y the Y coordinate >= 0
0796             * @param a the allocated region to render into
0797             * @return the location within the model that best represents the
0798             *  given point in the view >= 0.  The biasReturn argument will be
0799             * filled in to indicate that the point given is closer to the next
0800             * character in the model or the previous character in the model.
0801             */
0802            public int viewToModel(float x, float y, Shape a,
0803                    Position.Bias[] biasReturn) {
0804                int pos; // return position
0805                int index; // child index to forward to
0806                Shape ca; // child allocation
0807
0808                // locate the child view and it's allocation so that
0809                // we can forward to it.  Make sure the layout thread
0810                // doesn't change anything by trying to flush changes
0811                // to the parent while the GUI thread is trying to
0812                // find the child and it's allocation.
0813                synchronized (locator) {
0814                    index = locator.getViewIndexAtPoint(x, y, a);
0815                    ca = locator.getChildAllocation(index, a);
0816                }
0817
0818                // forward to the child view, and make sure we don't
0819                // interact with the layout thread by synchronizing
0820                // on the child state.
0821                ChildState cs = getChildState(index);
0822                synchronized (cs) {
0823                    View v = cs.getChildView();
0824                    pos = v.viewToModel(x, y, ca, biasReturn);
0825                }
0826                return pos;
0827            }
0828
0829            /**
0830             * Provides a way to determine the next visually represented model 
0831             * location that one might place a caret.  Some views may not be visible,
0832             * they might not be in the same order found in the model, or they just
0833             * might not allow access to some of the locations in the model.
0834             *
0835             * @param pos the position to convert >= 0
0836             * @param a the allocated region to render into
0837             * @param direction the direction from the current position that can
0838             *  be thought of as the arrow keys typically found on a keyboard;
0839             *  this may be one of the following: 
0840             *  <ul>
0841             *  <code>SwingConstants.WEST</code>
0842             *  <code>SwingConstants.EAST</code> 
0843             *  <code>SwingConstants.NORTH</code>
0844             *  <code>SwingConstants.SOUTH</code>  
0845             *  </ul>
0846             * @param biasRet an array contain the bias that was checked
0847             * @return the location within the model that best represents the next
0848             *  location visual position
0849             * @exception BadLocationException
0850             * @exception IllegalArgumentException if <code>direction</code> is invalid
0851             */
0852            public int getNextVisualPositionFrom(int pos, Position.Bias b,
0853                    Shape a, int direction, Position.Bias[] biasRet)
0854                    throws BadLocationException {
0855                return Utilities.getNextVisualPositionFrom(this , pos, b, a,
0856                        direction, biasRet);
0857            }
0858
0859            // --- variables -----------------------------------------
0860
0861            /**
0862             * The major axis against which the children are
0863             * tiled.
0864             */
0865            int axis;
0866
0867            /**
0868             * The children and their layout statistics.
0869             */
0870            java.util.List stats;
0871
0872            /**
0873             * Current span along the major axis.  This
0874             * is also the value returned by getMinimumSize,
0875             * getPreferredSize, and getMaximumSize along
0876             * the major axis.
0877             */
0878            float majorSpan;
0879
0880            /**
0881             * Is the span along the major axis estimated?
0882             */
0883            boolean estimatedMajorSpan;
0884
0885            /**
0886             * Current span along the minor axis.  This
0887             * is what layout was done against (i.e. things
0888             * are flexible in this direction).
0889             */
0890            float minorSpan;
0891
0892            /**
0893             * Object that manages the offsets of the 
0894             * children.  All locking for management of
0895             * child locations is on this object.
0896             */
0897            protected ChildLocator locator;
0898
0899            float topInset;
0900            float bottomInset;
0901            float leftInset;
0902            float rightInset;
0903
0904            ChildState minRequest;
0905            ChildState prefRequest;
0906            boolean majorChanged;
0907            boolean minorChanged;
0908            Runnable flushTask;
0909
0910            /**
0911             * Child that is actively changing size.  This often
0912             * causes a preferenceChanged, so this is a cache to
0913             * possibly speed up the marking the state.  It also
0914             * helps flag an opportunity to avoid adding to flush
0915             * task to the layout queue.
0916             */
0917            ChildState changing;
0918
0919            /**
0920             * A class to manage the effective position of the
0921             * child views in a localized area while changes are
0922             * being made around the localized area.  The AsyncBoxView
0923             * may be continuously changing, but the visible area
0924             * needs to remain fairly stable until the layout thread
0925             * decides to publish an update to the parent.
0926             * @since 1.3
0927             */
0928            public class ChildLocator {
0929
0930                /**
0931                 * construct a child locator.
0932                 */
0933                public ChildLocator() {
0934                    lastAlloc = new Rectangle();
0935                    childAlloc = new Rectangle();
0936                }
0937
0938                /**
0939                 * Notification that a child changed.  This can effect
0940                 * whether or not new offset calculations are needed.
0941                 * This is called by a ChildState object that has 
0942                 * changed it's major span.  This can therefore be
0943                 * called by multiple threads.
0944                 */
0945                public synchronized void childChanged(ChildState cs) {
0946                    if (lastValidOffset == null) {
0947                        lastValidOffset = cs;
0948                    } else if (cs.getChildView().getStartOffset() < lastValidOffset
0949                            .getChildView().getStartOffset()) {
0950                        lastValidOffset = cs;
0951                    }
0952                }
0953
0954                /**
0955                 * Paint the children that intersect the clip area.
0956                 */
0957                public synchronized void paintChildren(Graphics g) {
0958                    Rectangle clip = g.getClipBounds();
0959                    float targetOffset = (axis == X_AXIS) ? clip.x
0960                            - lastAlloc.x : clip.y - lastAlloc.y;
0961                    int index = getViewIndexAtVisualOffset(targetOffset);
0962                    int n = getViewCount();
0963                    float offs = getChildState(index).getMajorOffset();
0964                    for (int i = index; i < n; i++) {
0965                        ChildState cs = getChildState(i);
0966                        cs.setMajorOffset(offs);
0967                        Shape ca = getChildAllocation(i);
0968                        if (intersectsClip(ca, clip)) {
0969                            synchronized (cs) {
0970                                View v = cs.getChildView();
0971                                v.paint(g, ca);
0972                            }
0973                        } else {
0974                            // done painting intersection
0975                            break;
0976                        }
0977                        offs += cs.getMajorSpan();
0978                    }
0979                }
0980
0981                /**
0982                 * Fetch the allocation to use for a child view.
0983                 * This will update the offsets for all children
0984                 * not yet updated before the given index.
0985                 */
0986                public synchronized Shape getChildAllocation(int index, Shape a) {
0987                    if (a == null) {
0988                        return null;
0989                    }
0990                    setAllocation(a);
0991                    ChildState cs = getChildState(index);
0992                    if (lastValidOffset == null) {
0993                        lastValidOffset = getChildState(0);
0994                    }
0995                    if (cs.getChildView().getStartOffset() > lastValidOffset
0996                            .getChildView().getStartOffset()) {
0997                        // offsets need to be updated
0998                        updateChildOffsetsToIndex(index);
0999                    }
1000                    Shape ca = getChildAllocation(index);
1001                    return ca;
1002                }
1003
1004                /**
1005                 * Fetches the child view index at the given point.
1006                 * This is called by the various View methods that
1007                 * need to calculate which child to forward a message
1008                 * to.  This should be called by a block synchronized
1009                 * on this object, and would typically be followed
1010                 * with one or more calls to getChildAllocation that
1011                 * should also be in the synchronized block.
1012                 *
1013                 * @param x the X coordinate >= 0
1014                 * @param y the Y coordinate >= 0
1015                 * @param a the allocation to the View
1016                 * @return the nearest child index
1017                 */
1018                public int getViewIndexAtPoint(float x, float y, Shape a) {
1019                    setAllocation(a);
1020                    float targetOffset = (axis == X_AXIS) ? x - lastAlloc.x : y
1021                            - lastAlloc.y;
1022                    int index = getViewIndexAtVisualOffset(targetOffset);
1023                    return index;
1024                }
1025
1026                /**
1027                 * Fetch the allocation to use for a child view.
1028                 * <em>This does not update the offsets in the ChildState
1029                 * records.</em>
1030                 */
1031                protected Shape getChildAllocation(int index) {
1032                    ChildState cs = getChildState(index);
1033                    if (!cs.isLayoutValid()) {
1034                        cs.run();
1035                    }
1036                    if (axis == X_AXIS) {
1037                        childAlloc.x = lastAlloc.x + (int) cs.getMajorOffset();
1038                        childAlloc.y = lastAlloc.y + (int) cs.getMinorOffset();
1039                        childAlloc.width = (int) cs.getMajorSpan();
1040                        childAlloc.height = (int) cs.getMinorSpan();
1041                    } else {
1042                        childAlloc.y = lastAlloc.y + (int) cs.getMajorOffset();
1043                        childAlloc.x = lastAlloc.x + (int) cs.getMinorOffset();
1044                        childAlloc.height = (int) cs.getMajorSpan();
1045                        childAlloc.width = (int) cs.getMinorSpan();
1046                    }
1047                    childAlloc.x += (int) getLeftInset();
1048                    childAlloc.y += (int) getRightInset();
1049                    return childAlloc;
1050                }
1051
1052                /**
1053                 * Copy the currently allocated shape into the Rectangle
1054                 * used to store the current allocation.  This would be 
1055                 * a floating point rectangle in a Java2D-specific implmentation.
1056                 */
1057                protected void setAllocation(Shape a) {
1058                    if (a instanceof  Rectangle) {
1059                        lastAlloc.setBounds((Rectangle) a);
1060                    } else {
1061                        lastAlloc.setBounds(a.getBounds());
1062                    }
1063                    setSize(lastAlloc.width, lastAlloc.height);
1064                }
1065
1066                /**
1067                 * Locate the view responsible for an offset into the box
1068                 * along the major axis.  Make sure that offsets are set
1069                 * on the ChildState objects up to the given target span
1070                 * past the desired offset.
1071                 *
1072                 * @return   index of the view representing the given visual
1073                 *   location (targetOffset), or -1 if no view represents 
1074                 *   that location
1075                 */
1076                protected int getViewIndexAtVisualOffset(float targetOffset) {
1077                    int n = getViewCount();
1078                    if (n > 0) {
1079                        boolean lastValid = (lastValidOffset != null);
1080
1081                        if (lastValidOffset == null) {
1082                            lastValidOffset = getChildState(0);
1083                        }
1084                        if (targetOffset > majorSpan) {
1085                            // should only get here on the first time display.
1086                            if (!lastValid) {
1087                                return 0;
1088                            }
1089                            int pos = lastValidOffset.getChildView()
1090                                    .getStartOffset();
1091                            int index = getViewIndex(pos, Position.Bias.Forward);
1092                            return index;
1093                        } else if (targetOffset > lastValidOffset
1094                                .getMajorOffset()) {
1095                            // roll offset calculations forward
1096                            return updateChildOffsets(targetOffset);
1097                        } else {
1098                            // no changes prior to the needed offset
1099                            // this should be a binary search
1100                            float offs = 0f;
1101                            for (int i = 0; i < n; i++) {
1102                                ChildState cs = getChildState(i);
1103                                float nextOffs = offs + cs.getMajorSpan();
1104                                if (targetOffset < nextOffs) {
1105                                    return i;
1106                                }
1107                                offs = nextOffs;
1108                            }
1109                        }
1110                    }
1111                    return n - 1;
1112                }
1113
1114                /**
1115                 * Move the location of the last offset calculation forward
1116                 * to the desired offset.
1117                 */
1118                int updateChildOffsets(float targetOffset) {
1119                    int n = getViewCount();
1120                    int targetIndex = n - 1;
1121                    ;
1122                    int pos = lastValidOffset.getChildView().getStartOffset();
1123                    int startIndex = getViewIndex(pos, Position.Bias.Forward);
1124                    float start = lastValidOffset.getMajorOffset();
1125                    float lastOffset = start;
1126                    for (int i = startIndex; i < n; i++) {
1127                        ChildState cs = getChildState(i);
1128                        cs.setMajorOffset(lastOffset);
1129                        lastOffset += cs.getMajorSpan();
1130                        if (targetOffset < lastOffset) {
1131                            targetIndex = i;
1132                            lastValidOffset = cs;
1133                            break;
1134                        }
1135                    }
1136
1137                    return targetIndex;
1138                }
1139
1140                /**
1141                 * Move the location of the last offset calculation forward
1142                 * to the desired index.
1143                 */
1144                void updateChildOffsetsToIndex(int index) {
1145                    int pos = lastValidOffset.getChildView().getStartOffset();
1146                    int startIndex = getViewIndex(pos, Position.Bias.Forward);
1147                    float lastOffset = lastValidOffset.getMajorOffset();
1148                    for (int i = startIndex; i <= index; i++) {
1149                        ChildState cs = getChildState(i);
1150                        cs.setMajorOffset(lastOffset);
1151                        lastOffset += cs.getMajorSpan();
1152                    }
1153                }
1154
1155                boolean intersectsClip(Shape childAlloc, Rectangle clip) {
1156                    Rectangle cs = (childAlloc instanceof  Rectangle) ? (Rectangle) childAlloc
1157                            : childAlloc.getBounds();
1158                    if (cs.intersects(clip)) {
1159                        // Make sure that lastAlloc also contains childAlloc,
1160                        // this will be false if haven't yet flushed changes.
1161                        return lastAlloc.intersects(cs);
1162                    }
1163                    return false;
1164                }
1165
1166                /**
1167                 * The location of the last offset calculation
1168                 * that is valid.
1169                 */
1170                protected ChildState lastValidOffset;
1171
1172                /**
1173                 * The last seen allocation (for repainting when changes
1174                 * are flushed upward).
1175                 */
1176                protected Rectangle lastAlloc;
1177
1178                /**
1179                 * A shape to use for the child allocation to avoid
1180                 * creating a lot of garbage.  
1181                 */
1182                protected Rectangle childAlloc;
1183            }
1184
1185            /**
1186             * A record representing the layout state of a 
1187             * child view.  It is runnable as a task on another 
1188             * thread.  All access to the child view that is
1189             * based upon a read-lock on the model should synchronize
1190             * on this object (i.e. The layout thread and the GUI
1191             * thread can both have a read lock on the model at the 
1192             * same time and are not protected from each other).
1193             * Access to a child view hierarchy is serialized via
1194             * synchronization on the ChildState instance.
1195             * @since 1.3
1196             */
1197            public class ChildState implements  Runnable {
1198
1199                /**
1200                 * Construct a child status.  This needs to start
1201                 * out as fairly large so we don't falsely begin with
1202                 * the idea that all of the children are visible.
1203                 * @since 1.4
1204                 */
1205                public ChildState(View v) {
1206                    child = v;
1207                    minorValid = false;
1208                    majorValid = false;
1209                    childSizeValid = false;
1210                    child.setParent(AsyncBoxView.this );
1211                }
1212
1213                /**
1214                 * Fetch the child view this record represents
1215                 */
1216                public View getChildView() {
1217                    return child;
1218                }
1219
1220                /**
1221                 * Update the child state.  This should be
1222                 * called by the thread that desires to spend
1223                 * time updating the child state (intended to
1224                 * be the layout thread).
1225                 * <p>
1226                 * This aquires a read lock on the associated 
1227                 * document for the duration of the update to
1228                 * ensure the model is not changed while it is
1229                 * operating.  The first thing to do would be
1230                 * to see if any work actually needs to be done.
1231                 * The following could have conceivably happened
1232                 * while the state was waiting to be updated:
1233                 * <ol>
1234                 * <li>The child may have been removed from the
1235                 * view hierarchy.
1236                 * <li>The child may have been updated by a 
1237                 * higher priority operation (i.e. the child
1238                 * may have become visible).
1239                 * </ol>
1240                 */
1241                public void run() {
1242                    AbstractDocument doc = (AbstractDocument) getDocument();
1243                    try {
1244                        doc.readLock();
1245                        if (minorValid && majorValid && childSizeValid) {
1246                            // nothing to do
1247                            return;
1248                        }
1249                        if (child.getParent() == AsyncBoxView.this ) {
1250                            // this may overwrite anothers threads cached
1251                            // value for actively changing... but that just
1252                            // means it won't use the cache if there is an
1253                            // overwrite.
1254                            synchronized (AsyncBoxView.this ) {
1255                                changing = this ;
1256                            }
1257                            updateChild();
1258                            synchronized (AsyncBoxView.this ) {
1259                                changing = null;
1260                            }
1261
1262                            // setting the child size on the minor axis
1263                            // may have caused it to change it's preference
1264                            // along the major axis.
1265                            updateChild();
1266                        }
1267                    } finally {
1268                        doc.readUnlock();
1269                    }
1270                }
1271
1272                void updateChild() {
1273                    boolean minorUpdated = false;
1274                    synchronized (this ) {
1275                        if (!minorValid) {
1276                            int minorAxis = getMinorAxis();
1277                            min = child.getMinimumSpan(minorAxis);
1278                            pref = child.getPreferredSpan(minorAxis);
1279                            max = child.getMaximumSpan(minorAxis);
1280                            minorValid = true;
1281                            minorUpdated = true;
1282                        }
1283                    }
1284                    if (minorUpdated) {
1285                        minorRequirementChange(this );
1286                    }
1287
1288                    boolean majorUpdated = false;
1289                    float delta = 0.0f;
1290                    synchronized (this ) {
1291                        if (!majorValid) {
1292                            float old = span;
1293                            span = child.getPreferredSpan(axis);
1294                            delta = span - old;
1295                            majorValid = true;
1296                            majorUpdated = true;
1297                        }
1298                    }
1299                    if (majorUpdated) {
1300                        majorRequirementChange(this , delta);
1301                        locator.childChanged(this );
1302                    }
1303
1304                    synchronized (this ) {
1305                        if (!childSizeValid) {
1306                            float w;
1307                            float h;
1308                            if (axis == X_AXIS) {
1309                                w = span;
1310                                h = getMinorSpan();
1311                            } else {
1312                                w = getMinorSpan();
1313                                h = span;
1314                            }
1315                            childSizeValid = true;
1316                            child.setSize(w, h);
1317                        }
1318                    }
1319
1320                }
1321
1322                /**
1323                 * What is the span along the minor axis.
1324                 */
1325                public float getMinorSpan() {
1326                    if (max < minorSpan) {
1327                        return max;
1328                    }
1329                    // make it the target width, or as small as it can get.
1330                    return Math.max(min, minorSpan);
1331                }
1332
1333                /**
1334                 * What is the offset along the minor axis
1335                 */
1336                public float getMinorOffset() {
1337                    if (max < minorSpan) {
1338                        // can't make the child this wide, align it
1339                        float align = child.getAlignment(getMinorAxis());
1340                        return ((minorSpan - max) * align);
1341                    }
1342                    return 0f;
1343                }
1344
1345                /**
1346                 * What is the span along the major axis. 
1347                 */
1348                public float getMajorSpan() {
1349                    return span;
1350                }
1351
1352                /**
1353                 * Get the offset along the major axis
1354                 */
1355                public float getMajorOffset() {
1356                    return offset;
1357                }
1358
1359                /**
1360                 * This method should only be called by the ChildLocator,
1361                 * it is simply a convenient place to hold the cached
1362                 * location.
1363                 */
1364                public void setMajorOffset(float offs) {
1365                    offset = offs;
1366                }
1367
1368                /**
1369                 * Mark preferences changed for this child.
1370                 *
1371                 * @param width true if the width preference has changed
1372                 * @param height true if the height preference has changed
1373                 * @see javax.swing.JComponent#revalidate
1374                 */
1375                public void preferenceChanged(boolean width, boolean height) {
1376                    if (axis == X_AXIS) {
1377                        if (width) {
1378                            majorValid = false;
1379                        }
1380                        if (height) {
1381                            minorValid = false;
1382                        }
1383                    } else {
1384                        if (width) {
1385                            minorValid = false;
1386                        }
1387                        if (height) {
1388                            majorValid = false;
1389                        }
1390                    }
1391                    childSizeValid = false;
1392                }
1393
1394                /**
1395                 * Has the child view been laid out.
1396                 */
1397                public boolean isLayoutValid() {
1398                    return (minorValid && majorValid && childSizeValid);
1399                }
1400
1401                // minor axis
1402                private float min;
1403                private float pref;
1404                private float max;
1405                private float align;
1406                private boolean minorValid;
1407
1408                // major axis
1409                private float span;
1410                private float offset;
1411                private boolean majorValid;
1412
1413                private View child;
1414                private boolean childSizeValid;
1415            }
1416
1417            /**
1418             * Task to flush requirement changes upward
1419             */
1420            class FlushTask implements  Runnable {
1421
1422                public void run() {
1423                    flushRequirementChanges();
1424                }
1425
1426            }
1427
1428        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.