Source Code Cross Referenced for FlowView.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) 


001        /*
002         * Copyright 1999-2006 Sun Microsystems, Inc.  All Rights Reserved.
003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004         *
005         * This code is free software; you can redistribute it and/or modify it
006         * under the terms of the GNU General Public License version 2 only, as
007         * published by the Free Software Foundation.  Sun designates this
008         * particular file as subject to the "Classpath" exception as provided
009         * by Sun in the LICENSE file that accompanied this code.
010         *
011         * This code is distributed in the hope that it will be useful, but WITHOUT
012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014         * version 2 for more details (a copy is included in the LICENSE file that
015         * accompanied this code).
016         *
017         * You should have received a copy of the GNU General Public License version
018         * 2 along with this work; if not, write to the Free Software Foundation,
019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020         *
021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022         * CA 95054 USA or visit www.sun.com if you need additional information or
023         * have any questions.
024         */
025        package javax.swing.text;
026
027        import java.awt.*;
028        import java.util.Vector;
029        import javax.swing.event.*;
030        import javax.swing.SizeRequirements;
031
032        /**
033         * A View that tries to flow it's children into some 
034         * partially constrained space.  This can be used to
035         * build things like paragraphs, pages, etc.  The 
036         * flow is made up of the following pieces of functionality.
037         * <ul>
038         * <li>A logical set of child views, which as used as a
039         * layout pool from which a physical view is formed.
040         * <li>A strategy for translating the logical view to
041         * a physical (flowed) view.
042         * <li>Constraints for the strategy to work against.
043         * <li>A physical structure, that represents the flow.
044         * The children of this view are where the pieces of 
045         * of the logical views are placed to create the flow.
046         * </ul>
047         *
048         * @author  Timothy Prinzing
049         * @version 1.60 05/05/07
050         * @see     View
051         * @since 1.3
052         */
053        public abstract class FlowView extends BoxView {
054
055            /**
056             * Constructs a FlowView for the given element.
057             *
058             * @param elem the element that this view is responsible for
059             * @param axis may be either View.X_AXIS or View.Y_AXIS
060             */
061            public FlowView(Element elem, int axis) {
062                super (elem, axis);
063                layoutSpan = Integer.MAX_VALUE;
064                strategy = new FlowStrategy();
065            }
066
067            /**
068             * Fetches the axis along which views should be
069             * flowed.  By default, this will be the axis 
070             * orthogonal to the axis along which the flow
071             * rows are tiled (the axis of the default flow
072             * rows themselves).  This is typically used
073             * by the <code>FlowStrategy</code>.
074             */
075            public int getFlowAxis() {
076                if (getAxis() == Y_AXIS) {
077                    return X_AXIS;
078                }
079                return Y_AXIS;
080            }
081
082            /**
083             * Fetch the constraining span to flow against for
084             * the given child index.  This is called by the
085             * FlowStrategy while it is updating the flow.
086             * A flow can be shaped by providing different values
087             * for the row constraints.  By default, the entire
088             * span inside of the insets along the flow axis
089             * is returned.
090             *
091             * @param index the index of the row being updated.
092             *   This should be a value >= 0 and < getViewCount().
093             * @see #getFlowStart
094             */
095            public int getFlowSpan(int index) {
096                return layoutSpan;
097            }
098
099            /**
100             * Fetch the location along the flow axis that the
101             * flow span will start at.  This is called by the
102             * FlowStrategy while it is updating the flow.
103             * A flow can be shaped by providing different values
104             * for the row constraints.
105
106             * @param index the index of the row being updated.
107             *   This should be a value >= 0 and < getViewCount().
108             * @see #getFlowSpan
109             */
110            public int getFlowStart(int index) {
111                return 0;
112            }
113
114            /**
115             * Create a View that should be used to hold a 
116             * a rows worth of children in a flow.  This is
117             * called by the FlowStrategy when new children
118             * are added or removed (i.e. rows are added or
119             * removed) in the process of updating the flow.
120             */
121            protected abstract View createRow();
122
123            // ---- BoxView methods -------------------------------------
124
125            /**
126             * Loads all of the children to initialize the view.
127             * This is called by the <code>setParent</code> method.
128             * This is reimplemented to not load any children directly
129             * (as they are created in the process of formatting).
130             * If the layoutPool variable is null, an instance of
131             * LogicalView is created to represent the logical view
132             * that is used in the process of formatting.
133             *
134             * @param f the view factory
135             */
136            protected void loadChildren(ViewFactory f) {
137                if (layoutPool == null) {
138                    layoutPool = new LogicalView(getElement());
139                }
140                layoutPool.setParent(this );
141
142                // This synthetic insertUpdate call gives the strategy a chance
143                // to initialize.
144                strategy.insertUpdate(this , null, null);
145            }
146
147            /**
148             * Fetches the child view index representing the given position in
149             * the model.  
150             *
151             * @param pos the position >= 0
152             * @return  index of the view representing the given position, or 
153             *   -1 if no view represents that position
154             */
155            protected int getViewIndexAtPosition(int pos) {
156                if (pos >= getStartOffset() && (pos < getEndOffset())) {
157                    for (int counter = 0; counter < getViewCount(); counter++) {
158                        View v = getView(counter);
159                        if (pos >= v.getStartOffset() && pos < v.getEndOffset()) {
160                            return counter;
161                        }
162                    }
163                }
164                return -1;
165            }
166
167            /**
168             * Lays out the children.  If the span along the flow
169             * axis has changed, layout is marked as invalid which
170             * which will cause the superclass behavior to recalculate
171             * the layout along the box axis.  The FlowStrategy.layout
172             * method will be called to rebuild the flow rows as 
173             * appropriate.  If the height of this view changes 
174             * (determined by the perferred size along the box axis),
175             * a preferenceChanged is called.  Following all of that,
176             * the normal box layout of the superclass is performed.
177             *
178             * @param width  the width to lay out against >= 0.  This is
179             *   the width inside of the inset area.
180             * @param height the height to lay out against >= 0 This
181             *   is the height inside of the inset area.
182             */
183            protected void layout(int width, int height) {
184                final int faxis = getFlowAxis();
185                int newSpan;
186                if (faxis == X_AXIS) {
187                    newSpan = (int) width;
188                } else {
189                    newSpan = (int) height;
190                }
191                if (layoutSpan != newSpan) {
192                    layoutChanged(faxis);
193                    layoutChanged(getAxis());
194                    layoutSpan = newSpan;
195                }
196
197                // repair the flow if necessary
198                if (!isLayoutValid(faxis)) {
199                    final int heightAxis = getAxis();
200                    int oldFlowHeight = (int) ((heightAxis == X_AXIS) ? getWidth()
201                            : getHeight());
202                    strategy.layout(this );
203                    int newFlowHeight = (int) getPreferredSpan(heightAxis);
204                    if (oldFlowHeight != newFlowHeight) {
205                        View p = getParent();
206                        if (p != null) {
207                            p.preferenceChanged(this , (heightAxis == X_AXIS),
208                                    (heightAxis == Y_AXIS));
209                        }
210
211                        // PENDING(shannonh)
212                        // Temporary fix for 4250847
213                        // Can be removed when TraversalContext is added
214                        Component host = getContainer();
215                        if (host != null) {
216                            //nb idk 12/12/2001 host should not be equal to null. We need to add assertion here
217                            host.repaint();
218                        }
219                    }
220                }
221
222                super .layout(width, height);
223            }
224
225            /**
226             * Calculate equirements along the minor axis.  This
227             * is implemented to forward the request to the logical 
228             * view by calling getMinimumSpan, getPreferredSpan, and
229             * getMaximumSpan on it.  
230             */
231            protected SizeRequirements calculateMinorAxisRequirements(int axis,
232                    SizeRequirements r) {
233                if (r == null) {
234                    r = new SizeRequirements();
235                }
236                float pref = layoutPool.getPreferredSpan(axis);
237                float min = layoutPool.getMinimumSpan(axis);
238                // Don't include insets, Box.getXXXSpan will include them.
239                r.minimum = (int) min;
240                r.preferred = Math.max(r.minimum, (int) pref);
241                r.maximum = Integer.MAX_VALUE;
242                r.alignment = 0.5f;
243                return r;
244            }
245
246            // ---- View methods ----------------------------------------------------
247
248            /**
249             * Gives notification that something was inserted into the document
250             * in a location that this view is responsible for.
251             *
252             * @param changes the change information from the associated document
253             * @param a the current allocation of the view
254             * @param f the factory to use to rebuild if the view has children
255             * @see View#insertUpdate
256             */
257            public void insertUpdate(DocumentEvent changes, Shape a,
258                    ViewFactory f) {
259                layoutPool.insertUpdate(changes, a, f);
260                strategy.insertUpdate(this , changes, getInsideAllocation(a));
261            }
262
263            /**
264             * Gives notification that something was removed from the document
265             * in a location that this view is responsible for.
266             *
267             * @param changes the change information from the associated document
268             * @param a the current allocation of the view
269             * @param f the factory to use to rebuild if the view has children
270             * @see View#removeUpdate
271             */
272            public void removeUpdate(DocumentEvent changes, Shape a,
273                    ViewFactory f) {
274                layoutPool.removeUpdate(changes, a, f);
275                strategy.removeUpdate(this , changes, getInsideAllocation(a));
276            }
277
278            /**
279             * Gives notification from the document that attributes were changed
280             * in a location that this view is responsible for.
281             *
282             * @param changes the change information from the associated document
283             * @param a the current allocation of the view
284             * @param f the factory to use to rebuild if the view has children
285             * @see View#changedUpdate
286             */
287            public void changedUpdate(DocumentEvent changes, Shape a,
288                    ViewFactory f) {
289                layoutPool.changedUpdate(changes, a, f);
290                strategy.changedUpdate(this , changes, getInsideAllocation(a));
291            }
292
293            /** {@inheritDoc} */
294            public void setParent(View parent) {
295                super .setParent(parent);
296                if (parent == null && layoutPool != null) {
297                    layoutPool.setParent(null);
298                }
299            }
300
301            // --- variables -----------------------------------------------
302
303            /**
304             * Default constraint against which the flow is 
305             * created against.  
306             */
307            protected int layoutSpan;
308
309            /**
310             * These are the views that represent the child elements
311             * of the element this view represents (The logical view
312             * to translate to a physical view).  These are not
313             * directly children of this view.  These are either 
314             * placed into the rows directly or used for the purpose
315             * of breaking into smaller chunks, to form the physical
316             * view.
317             */
318            protected View layoutPool;
319
320            /**
321             * The behavior for keeping the flow updated.  By
322             * default this is a singleton shared by all instances
323             * of FlowView (FlowStrategy is stateless).  Subclasses
324             * can create an alternative strategy, which might keep
325             * state.
326             */
327            protected FlowStrategy strategy;
328
329            /**
330             * Strategy for maintaining the physical form
331             * of the flow.  The default implementation is
332             * completely stateless, and recalculates the
333             * entire flow if the layout is invalid on the
334             * given FlowView.  Alternative strategies can
335             * be implemented by subclassing, and might 
336             * perform incrementatal repair to the layout
337             * or alternative breaking behavior.
338             * @since 1.3
339             */
340            public static class FlowStrategy {
341                int damageStart = Integer.MAX_VALUE;
342                Vector<View> viewBuffer;
343
344                void addDamage(FlowView fv, int offset) {
345                    if (offset >= fv.getStartOffset()
346                            && offset < fv.getEndOffset()) {
347                        damageStart = Math.min(damageStart, offset);
348                    }
349                }
350
351                void unsetDamage() {
352                    damageStart = Integer.MAX_VALUE;
353                }
354
355                /**
356                 * Gives notification that something was inserted into the document
357                 * in a location that the given flow view is responsible for.  The
358                 * strategy should update the appropriate changed region (which
359                 * depends upon the strategy used for repair).
360                 *
361                 * @param e the change information from the associated document
362                 * @param alloc the current allocation of the view inside of the insets.
363                 *   This value will be null if the view has not yet been displayed.
364                 * @see View#insertUpdate
365                 */
366                public void insertUpdate(FlowView fv, DocumentEvent e,
367                        Rectangle alloc) {
368                    // FlowView.loadChildren() makes a synthetic call into this,
369                    // passing null as e
370                    if (e != null) {
371                        addDamage(fv, e.getOffset());
372                    }
373
374                    if (alloc != null) {
375                        Component host = fv.getContainer();
376                        if (host != null) {
377                            host.repaint(alloc.x, alloc.y, alloc.width,
378                                    alloc.height);
379                        }
380                    } else {
381                        fv.preferenceChanged(null, true, true);
382                    }
383                }
384
385                /**
386                 * Gives notification that something was removed from the document
387                 * in a location that the given flow view is responsible for.
388                 *
389                 * @param e the change information from the associated document
390                 * @param alloc the current allocation of the view inside of the insets.
391                 * @see View#removeUpdate
392                 */
393                public void removeUpdate(FlowView fv, DocumentEvent e,
394                        Rectangle alloc) {
395                    addDamage(fv, e.getOffset());
396                    if (alloc != null) {
397                        Component host = fv.getContainer();
398                        if (host != null) {
399                            host.repaint(alloc.x, alloc.y, alloc.width,
400                                    alloc.height);
401                        }
402                    } else {
403                        fv.preferenceChanged(null, true, true);
404                    }
405                }
406
407                /**
408                 * Gives notification from the document that attributes were changed
409                 * in a location that this view is responsible for.
410                 *
411                 * @param fv     the <code>FlowView</code> containing the changes
412                 * @param e      the <code>DocumentEvent</code> describing the changes
413                 *               done to the Document
414                 * @param alloc  Bounds of the View
415                 * @see View#changedUpdate
416                 */
417                public void changedUpdate(FlowView fv, DocumentEvent e,
418                        Rectangle alloc) {
419                    addDamage(fv, e.getOffset());
420                    if (alloc != null) {
421                        Component host = fv.getContainer();
422                        if (host != null) {
423                            host.repaint(alloc.x, alloc.y, alloc.width,
424                                    alloc.height);
425                        }
426                    } else {
427                        fv.preferenceChanged(null, true, true);
428                    }
429                }
430
431                /**
432                 * This method gives flow strategies access to the logical
433                 * view of the FlowView.
434                 */
435                protected View getLogicalView(FlowView fv) {
436                    return fv.layoutPool;
437                }
438
439                /** 
440                 * Update the flow on the given FlowView.  By default, this causes 
441                 * all of the rows (child views) to be rebuilt to match the given 
442                 * constraints for each row.  This is called by a FlowView.layout 
443                 * to update the child views in the flow.
444                 *
445                 * @param fv the view to reflow
446                 */
447                public void layout(FlowView fv) {
448                    View pool = getLogicalView(fv);
449                    int rowIndex, p0;
450                    int p1 = fv.getEndOffset();
451
452                    if (fv.majorAllocValid) {
453                        if (damageStart == Integer.MAX_VALUE) {
454                            return;
455                        }
456                        // In some cases there's no view at position damageStart, so
457                        // step back and search again. See 6452106 for details.
458                        while ((rowIndex = fv
459                                .getViewIndexAtPosition(damageStart)) < 0) {
460                            damageStart--;
461                        }
462                        if (rowIndex > 0) {
463                            rowIndex--;
464                        }
465                        p0 = fv.getView(rowIndex).getStartOffset();
466                    } else {
467                        rowIndex = 0;
468                        p0 = fv.getStartOffset();
469                    }
470                    reparentViews(pool, p0);
471
472                    viewBuffer = new Vector<View>(10, 10);
473                    int rowCount = fv.getViewCount();
474                    while (p0 < p1) {
475                        View row;
476                        if (rowIndex >= rowCount) {
477                            row = fv.createRow();
478                            fv.append(row);
479                        } else {
480                            row = fv.getView(rowIndex);
481                        }
482                        p0 = layoutRow(fv, rowIndex, p0);
483                        rowIndex++;
484                    }
485                    viewBuffer = null;
486
487                    if (rowIndex < rowCount) {
488                        fv.replace(rowIndex, rowCount - rowIndex, null);
489                    }
490                    unsetDamage();
491                }
492
493                /**
494                 * Creates a row of views that will fit within the 
495                 * layout span of the row.  This is called by the layout method.
496                 * This is implemented to fill the row by repeatedly calling
497                 * the createView method until the available span has been
498                 * exhausted, a forced break was encountered, or the createView
499                 * method returned null.  If the remaining span was exhaused, 
500                 * the adjustRow method will be called to perform adjustments
501                 * to the row to try and make it fit into the given span.
502                 *
503                 * @param rowIndex the index of the row to fill in with views.  The
504                 *   row is assumed to be empty on entry.
505                 * @param pos  The current position in the children of
506                 *   this views element from which to start.  
507                 * @return the position to start the next row
508                 */
509                protected int layoutRow(FlowView fv, int rowIndex, int pos) {
510                    View row = fv.getView(rowIndex);
511                    float x = fv.getFlowStart(rowIndex);
512                    float spanLeft = fv.getFlowSpan(rowIndex);
513                    int end = fv.getEndOffset();
514                    TabExpander te = (fv instanceof  TabExpander) ? (TabExpander) fv
515                            : null;
516                    final int flowAxis = fv.getFlowAxis();
517
518                    int breakWeight = BadBreakWeight;
519                    float breakX = 0f;
520                    float breakSpan = 0f;
521                    int breakIndex = -1;
522                    int n = 0;
523
524                    viewBuffer.clear();
525                    while (pos < end && spanLeft >= 0) {
526                        View v = createView(fv, pos, (int) spanLeft, rowIndex);
527                        if (v == null) {
528                            break;
529                        }
530
531                        int bw = v.getBreakWeight(flowAxis, x, spanLeft);
532                        if (bw >= ForcedBreakWeight) {
533                            View w = v.breakView(flowAxis, pos, x, spanLeft);
534                            if (w != null) {
535                                viewBuffer.add(w);
536                            } else if (n == 0) {
537                                // if the view does not break, and it is the only view
538                                // in a row, use the whole view
539                                viewBuffer.add(v);
540                            }
541                            break;
542                        } else if (bw >= breakWeight && bw > BadBreakWeight) {
543                            breakWeight = bw;
544                            breakX = x;
545                            breakSpan = spanLeft;
546                            breakIndex = n;
547                        }
548
549                        float chunkSpan;
550                        if (flowAxis == X_AXIS && v instanceof  TabableView) {
551                            chunkSpan = ((TabableView) v).getTabbedSpan(x, te);
552                        } else {
553                            chunkSpan = v.getPreferredSpan(flowAxis);
554                        }
555
556                        if (chunkSpan > spanLeft && breakIndex >= 0) {
557                            // row is too long, and we may break
558                            if (breakIndex < n) {
559                                v = viewBuffer.get(breakIndex);
560                            }
561                            for (int i = n - 1; i >= breakIndex; i--) {
562                                viewBuffer.remove(i);
563                            }
564                            v = v.breakView(flowAxis, v.getStartOffset(),
565                                    breakX, breakSpan);
566                        }
567
568                        spanLeft -= chunkSpan;
569                        x += chunkSpan;
570                        viewBuffer.add(v);
571                        pos = v.getEndOffset();
572                        n++;
573                    }
574
575                    View[] views = new View[viewBuffer.size()];
576                    viewBuffer.toArray(views);
577                    row.replace(0, row.getViewCount(), views);
578                    return (views.length > 0 ? row.getEndOffset() : pos);
579                }
580
581                /**
582                 * Adjusts the given row if possible to fit within the
583                 * layout span.  By default this will try to find the 
584                 * highest break weight possible nearest the end of
585                 * the row.  If a forced break is encountered, the
586                 * break will be positioned there.
587                 * 
588                 * @param rowIndex the row to adjust to the current layout
589                 *  span.
590                 * @param desiredSpan the current layout span >= 0
591                 * @param x the location r starts at.
592                 */
593                protected void adjustRow(FlowView fv, int rowIndex,
594                        int desiredSpan, int x) {
595                    final int flowAxis = fv.getFlowAxis();
596                    View r = fv.getView(rowIndex);
597                    int n = r.getViewCount();
598                    int span = 0;
599                    int bestWeight = BadBreakWeight;
600                    int bestSpan = 0;
601                    int bestIndex = -1;
602                    View v;
603                    for (int i = 0; i < n; i++) {
604                        v = r.getView(i);
605                        int spanLeft = desiredSpan - span;
606
607                        int w = v.getBreakWeight(flowAxis, x + span, spanLeft);
608                        if ((w >= bestWeight) && (w > BadBreakWeight)) {
609                            bestWeight = w;
610                            bestIndex = i;
611                            bestSpan = span;
612                            if (w >= ForcedBreakWeight) {
613                                // it's a forced break, so there is
614                                // no point in searching further.
615                                break;
616                            }
617                        }
618                        span += v.getPreferredSpan(flowAxis);
619                    }
620                    if (bestIndex < 0) {
621                        // there is nothing that can be broken, leave
622                        // it in it's current state.
623                        return;
624                    }
625
626                    // Break the best candidate view, and patch up the row.
627                    int spanLeft = desiredSpan - bestSpan;
628                    v = r.getView(bestIndex);
629                    v = v.breakView(flowAxis, v.getStartOffset(), x + bestSpan,
630                            spanLeft);
631                    View[] va = new View[1];
632                    va[0] = v;
633                    View lv = getLogicalView(fv);
634                    int p0 = r.getView(bestIndex).getStartOffset();
635                    int p1 = r.getEndOffset();
636                    for (int i = 0; i < lv.getViewCount(); i++) {
637                        View tmpView = lv.getView(i);
638                        if (tmpView.getEndOffset() > p1) {
639                            break;
640                        }
641                        if (tmpView.getStartOffset() >= p0) {
642                            tmpView.setParent(lv);
643                        }
644                    }
645                    r.replace(bestIndex, n - bestIndex, va);
646                }
647
648                void reparentViews(View pool, int startPos) {
649                    int n = pool.getViewIndex(startPos, Position.Bias.Forward);
650                    if (n >= 0) {
651                        for (int i = n; i < pool.getViewCount(); i++) {
652                            pool.getView(i).setParent(pool);
653                        }
654                    }
655                }
656
657                /**
658                 * Creates a view that can be used to represent the current piece
659                 * of the flow.  This can be either an entire view from the
660                 * logical view, or a fragment of the logical view.
661                 *
662                 * @param fv the view holding the flow
663                 * @param startOffset the start location for the view being created
664                 * @param spanLeft the about of span left to fill in the row
665                 * @param rowIndex the row the view will be placed into
666                 */
667                protected View createView(FlowView fv, int startOffset,
668                        int spanLeft, int rowIndex) {
669                    // Get the child view that contains the given starting position
670                    View lv = getLogicalView(fv);
671                    int childIndex = lv.getViewIndex(startOffset,
672                            Position.Bias.Forward);
673                    View v = lv.getView(childIndex);
674                    if (startOffset == v.getStartOffset()) {
675                        // return the entire view
676                        return v;
677                    }
678
679                    // return a fragment.
680                    v = v.createFragment(startOffset, v.getEndOffset());
681                    return v;
682                }
683            }
684
685            /**
686             * This class can be used to represent a logical view for 
687             * a flow.  It keeps the children updated to reflect the state
688             * of the model, gives the logical child views access to the
689             * view hierarchy, and calculates a preferred span.  It doesn't
690             * do any rendering, layout, or model/view translation.
691             */
692            static class LogicalView extends CompositeView {
693
694                LogicalView(Element elem) {
695                    super (elem);
696                }
697
698                protected int getViewIndexAtPosition(int pos) {
699                    Element elem = getElement();
700                    if (elem.isLeaf()) {
701                        return 0;
702                    }
703                    return super .getViewIndexAtPosition(pos);
704                }
705
706                protected void loadChildren(ViewFactory f) {
707                    Element elem = getElement();
708                    if (elem.isLeaf()) {
709                        View v = new LabelView(elem);
710                        append(v);
711                    } else {
712                        super .loadChildren(f);
713                    }
714                }
715
716                /**
717                 * Fetches the attributes to use when rendering.  This view
718                 * isn't directly responsible for an element so it returns
719                 * the outer classes attributes.
720                 */
721                public AttributeSet getAttributes() {
722                    View p = getParent();
723                    return (p != null) ? p.getAttributes() : null;
724                }
725
726                /**
727                 * Determines the preferred span for this view along an
728                 * axis.
729                 *
730                 * @param axis may be either View.X_AXIS or View.Y_AXIS
731                 * @return   the span the view would like to be rendered into.
732                 *           Typically the view is told to render into the span
733                 *           that is returned, although there is no guarantee.  
734                 *           The parent may choose to resize or break the view.
735                 * @see View#getPreferredSpan
736                 */
737                public float getPreferredSpan(int axis) {
738                    float maxpref = 0;
739                    float pref = 0;
740                    int n = getViewCount();
741                    for (int i = 0; i < n; i++) {
742                        View v = getView(i);
743                        pref += v.getPreferredSpan(axis);
744                        if (v.getBreakWeight(axis, 0, Integer.MAX_VALUE) >= ForcedBreakWeight) {
745                            maxpref = Math.max(maxpref, pref);
746                            pref = 0;
747                        }
748                    }
749                    maxpref = Math.max(maxpref, pref);
750                    return maxpref;
751                }
752
753                /**
754                 * Determines the minimum span for this view along an
755                 * axis.  The is implemented to find the minimum unbreakable
756                 * span.
757                 *
758                 * @param axis may be either View.X_AXIS or View.Y_AXIS
759                 * @return  the span the view would like to be rendered into.
760                 *           Typically the view is told to render into the span
761                 *           that is returned, although there is no guarantee.  
762                 *           The parent may choose to resize or break the view.
763                 * @see View#getPreferredSpan
764                 */
765                public float getMinimumSpan(int axis) {
766                    float maxmin = 0;
767                    float min = 0;
768                    boolean nowrap = false;
769                    int n = getViewCount();
770                    for (int i = 0; i < n; i++) {
771                        View v = getView(i);
772                        if (v.getBreakWeight(axis, 0, Integer.MAX_VALUE) == BadBreakWeight) {
773                            min += v.getPreferredSpan(axis);
774                            nowrap = true;
775                        } else if (nowrap) {
776                            maxmin = Math.max(min, maxmin);
777                            nowrap = false;
778                            min = 0;
779                        }
780                        if (v instanceof  ComponentView) {
781                            maxmin = Math.max(maxmin, v.getMinimumSpan(axis));
782                        }
783                    }
784                    maxmin = Math.max(maxmin, min);
785                    return maxmin;
786                }
787
788                /**
789                 * Forward the DocumentEvent to the given child view.  This
790                 * is implemented to reparent the child to the logical view
791                 * (the children may have been parented by a row in the flow
792                 * if they fit without breaking) and then execute the superclass 
793                 * behavior.
794                 *
795                 * @param v the child view to forward the event to.
796                 * @param e the change information from the associated document
797                 * @param a the current allocation of the view
798                 * @param f the factory to use to rebuild if the view has children
799                 * @see #forwardUpdate
800                 * @since 1.3
801                 */
802                protected void forwardUpdateToView(View v, DocumentEvent e,
803                        Shape a, ViewFactory f) {
804                    View parent = v.getParent();
805                    v.setParent(this );
806                    super .forwardUpdateToView(v, e, a, f);
807                    v.setParent(parent);
808                }
809
810                // The following methods don't do anything useful, they
811                // simply keep the class from being abstract.
812
813                /**
814                 * Renders using the given rendering surface and area on that
815                 * surface.  This is implemented to do nothing, the logical
816                 * view is never visible.
817                 *
818                 * @param g the rendering surface to use
819                 * @param allocation the allocated region to render into
820                 * @see View#paint
821                 */
822                public void paint(Graphics g, Shape allocation) {
823                }
824
825                /**
826                 * Tests whether a point lies before the rectangle range.
827                 * Implemented to return false, as hit detection is not
828                 * performed on the logical view.
829                 *
830                 * @param x the X coordinate >= 0
831                 * @param y the Y coordinate >= 0
832                 * @param alloc the rectangle
833                 * @return true if the point is before the specified range
834                 */
835                protected boolean isBefore(int x, int y, Rectangle alloc) {
836                    return false;
837                }
838
839                /**
840                 * Tests whether a point lies after the rectangle range.
841                 * Implemented to return false, as hit detection is not
842                 * performed on the logical view.
843                 *
844                 * @param x the X coordinate >= 0
845                 * @param y the Y coordinate >= 0
846                 * @param alloc the rectangle
847                 * @return true if the point is after the specified range
848                 */
849                protected boolean isAfter(int x, int y, Rectangle alloc) {
850                    return false;
851                }
852
853                /**
854                 * Fetches the child view at the given point.
855                 * Implemented to return null, as hit detection is not
856                 * performed on the logical view.
857                 *
858                 * @param x the X coordinate >= 0
859                 * @param y the Y coordinate >= 0
860                 * @param alloc the parent's allocation on entry, which should
861                 *   be changed to the child's allocation on exit
862                 * @return the child view
863                 */
864                protected View getViewAtPoint(int x, int y, Rectangle alloc) {
865                    return null;
866                }
867
868                /**
869                 * Returns the allocation for a given child.
870                 * Implemented to do nothing, as the logical view doesn't
871                 * perform layout on the children.
872                 *
873                 * @param index the index of the child, >= 0 && < getViewCount()
874                 * @param a  the allocation to the interior of the box on entry, 
875                 *   and the allocation of the child view at the index on exit.
876                 */
877                protected void childAllocation(int index, Rectangle a) {
878                }
879            }
880
881        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.