KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > lib > editor > view > GapBoxView


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.lib.editor.view;
21
22 import java.awt.Component JavaDoc;
23 import java.awt.Graphics JavaDoc;
24 import java.awt.Rectangle JavaDoc;
25 import java.awt.Shape JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.List JavaDoc;
28 import javax.swing.event.DocumentEvent JavaDoc;
29 import javax.swing.text.AbstractDocument JavaDoc;
30 import javax.swing.text.AttributeSet JavaDoc;
31 import javax.swing.text.BadLocationException JavaDoc;
32 import javax.swing.text.Document JavaDoc;
33 import javax.swing.text.Element JavaDoc;
34 import javax.swing.text.LayoutQueue JavaDoc;
35 import javax.swing.text.Position JavaDoc;
36 import javax.swing.text.StyleConstants JavaDoc;
37 import javax.swing.text.View JavaDoc;
38 import javax.swing.text.ViewFactory JavaDoc;
39 import org.netbeans.editor.view.spi.EstimatedSpanView;
40 import org.netbeans.editor.view.spi.LockView;
41 import org.netbeans.editor.view.spi.ViewInsets;
42 import org.netbeans.editor.view.spi.ViewLayoutQueue;
43 import org.netbeans.editor.view.spi.ViewLayoutState;
44 import org.netbeans.editor.view.spi.ViewUtilities;
45 import org.netbeans.lib.editor.util.swing.ElementUtilities;
46
47 //import org.netbeans.spi.lexer.util.GapObjectArray;
48

49 /**
50  * Composite view implementation inspired
51  * by the {@link javax.swing.text.AsyncBoxView}
52  * holding its children in <code>GapObjectArray</code>
53  * and capable of posting complex layout changes
54  * into a separate layout thread.
55  * <br>
56  * This implementation is synchronous by default
57  * but it contains hooks where the asynchronous behavior
58  * can be installed.
59  *
60  * <p>
61  * The operation of this view relies on the presence
62  * of {@link LockView} under the root view in the view hierarchy.
63  * <br>
64  * All the view operation is expected to be single-threaded.
65  * <br>
66  * The view can only work with document instances
67  * extending {@link javax.swing.text.AbstractDocument}
68  * <br>
69  * The view effectively only operates with preferred spans
70  * of its children. However it can be extended
71  * to consider minimum and maximum spans as well
72  * if the particular layout algorithm would require it.
73  *
74  * <p>
75  * This view implementation separates information
76  * related to its children from the information required
77  * for its own operation. The children are kept in a separate object.
78  * <br>
79  * The view allows to release its children after the layout information
80  * for the whole view was determined but the view is not actively
81  * being rendered. Releasing of the children saves memory
82  * without loosing valuable information
83  * about view's own layout.
84  * <br>
85  * The view does not initialize its children
86  * upon call to {@link #setParent(javax.swing.text.View)}
87  * thus saving memory and cpu time.
88  * Only if it was previously asked for some information
89  * related to children (e.g. <code>getViewCount()</code>)
90  * or for preferred, minimum or maximum span of this view
91  * it will initialize them during <code>setParent()</code>.
92  * Once the parent view was set then the children
93  * are populated immediately once anyone asks
94  * for children related information or for spans.
95  *
96  * <p>
97  * The view can be constructed and work with element parameter being null.
98  * <br>
99  * The following things need to be ensured when using the view in such setup:
100  * <ul>
101  * <li> <code>getDocument()</code>,
102  * <code>getStartOffset()</code>,
103  * <code>getEndOffset()</code>,
104  * <code>getAttributes()</code>
105  * must be overriden to not delegate to element.
106  *
107  * <li> <code>insertUpdate()</code> and <code>removeUpdate()</code>
108  * methods will not find any element changes.
109  *
110  * <li> <code>reloadChildren()</code> should be revisited
111  * whether it will create possible children in a proper way.
112  *
113  * </ul>
114  *
115  * <p>
116  * Various constraints for using of this view implementation:
117  * <ul>
118  * <li> setParent() implementations of the views being added
119  * to this view are allowed to trigger
120  * <code>ViewLayoutState.Parent.majorAxisPreferenceChanged()</code>
121  * synchronously.
122  * <li> setParent() implementations of the views being added
123  * to this view are not allowed to add or remove another children
124  * synchronously.
125  * </ul>
126  *
127  * @author Miloslav Metelka
128  * @version 1.00
129  */

130
131 public class GapBoxView extends View JavaDoc
132 implements ViewLayoutState.Parent, ViewLayoutState,
133 EstimatedSpanView {
134     
135     private static final boolean debugRebuild
136         = Boolean.getBoolean("netbeans.debug.editor.view.rebuild"); // NOI18N
137

138     /**
139      * Bit value in <code>statusBits</code> determining
140      * whether X_AXIS is the major axis.
141      * <br>
142      * If this flag is not set then Y_AXIS
143      * is the major axis.
144      */

145     private static final int X_MAJOR_AXIS_BIT = 1;
146
147     /**
148      * Bit value in <code>statusBits</code> determining
149      * whether the major axis of this view
150      * is orthogonal to the major axis of the layout state
151      * that this view acts like.
152      */

153     private static final int MAJOR_AXES_ORTHOGONAL_BIT = 2;
154     
155     /**
156      * Bit value in <code>statusBits</code> determining
157      * whether preference for this view changed along the major axis.
158      */

159     private static final int MAJOR_AXIS_PREFERENCE_CHANGED_BIT = 4;
160     
161     /**
162      * Bit value in <code>statusBits</code> determining
163      * whether preference for this view changed along the minor axis.
164      */

165     private static final int MINOR_AXIS_PREFERENCE_CHANGED_BIT = 8;
166
167     /**
168      * Bit value in <code>statusBits</code> determining
169      * whether complete layout of the children has to be done
170      * during the next layout update of the children.
171      */

172     private static final int CHILDREN_LAYOUT_NECESSARY_BIT = 16;
173
174     /**
175      * Bit value in <code>statusBits</code> determining
176      * whether there are any pending repaint requests from children
177      * to be processed.
178      */

179     private static final int REPAINT_PENDING_BIT = 32;
180
181     /**
182      * Bit value in <code>statusBits</code> determining
183      * whether more than one view along the major axis
184      * needs to be repainted. The first view to repaint
185      * is determined by <code>firstRepaintChildIndex</code>.
186      * The whole area starting with the first view
187      * to repaint till the end of the view will be repainted.
188      */

189     private static final int REPAINT_TILL_END_BIT = 64;
190
191     /**
192      * Bit value in <code>statusBits</code> determining
193      * whether the preferred, minimum and maximum
194      * spans along the axes are estimated instead
195      * of measured exactly.
196      */

197     private static final int ESTIMATED_SPAN_BIT = 128;
198     
199     /**
200      * Bit value in <code>statusBits</code> determining
201      * whether the updateLayout() is currently being executed.
202      */

203     private static final int UPDATE_LAYOUT_IN_PROGRESS = 256;
204     
205     /**
206      * Bit value in <code>statusBits</code> determining
207      * whether this view is actively acting as layout state
208      * i.e. if it has parent view being instance
209      * of <code>ViewLayoutState.Parent</code>.
210      */

211     private static final int ACTIVE_LAYOUT_STATE = 512;
212     
213
214     // Bits related to this view acting as layout state follow
215

216     /**
217      * Bit value in <code>statusBits</code> determining
218      * whether the x is the major axis of this view
219      * participating as implementation of ViewLayoutState.
220      */

221     private static final int LAYOUT_STATE_X_MAJOR_AXIS_BIT
222         = (ACTIVE_LAYOUT_STATE << 1);
223
224     /**
225      * Bit value in <code>statusBits</code> determining
226      * that size of the view needs to be set again
227      * by <code>View.setSize()</code>
228      */

229     private static final int LAYOUT_STATE_VIEW_SIZE_INVALID_BIT
230         = (LAYOUT_STATE_X_MAJOR_AXIS_BIT << 1);
231     
232     /**
233      * Last bit in <code>statusBits</code> used for operation
234      * of this view. Subclasses may use higher bits if they want.
235      */

236     protected static final int GAP_BOX_VIEW_LAST_USED_STATUS_BIT
237         = LAYOUT_STATE_VIEW_SIZE_INVALID_BIT;
238     
239     /**
240      * Bit composition in <code>statusBits</code> determining
241      * whether any of the parameters affecting layout have
242      * changed and need to be updated.
243      */

244     private static final int LAYOUT_STATE_ANY_INVALID
245         = MAJOR_AXIS_PREFERENCE_CHANGED_BIT
246             | MINOR_AXIS_PREFERENCE_CHANGED_BIT
247             | LAYOUT_STATE_VIEW_SIZE_INVALID_BIT
248             | REPAINT_PENDING_BIT;
249
250     /**
251      * Composition of the bits forming the status of this view.
252      */

253     private int statusBits; // 16 bytes View + 4 = 20 bytes
254

255     /**
256      * Maintainer of </code>ViewLayoutState</code> children.
257      */

258     private GapBoxViewChildren children; // 20 + 4 = 24 bytes
259

260     /**
261      * Raw offset along the major axis of this view
262      * when acting as layout state.
263      */

264     private double layoutStateMajorAxisRawOffset; // 24 + 8 = 32 bytes
265

266     /**
267      * Raw index of this view in its parent
268      * when acting as layout state.
269      */

270     private int viewRawIndex; // 32 + 4 = 36 bytes
271

272     /**
273      * Cached preferred span along the major axis useful when this view acts
274      * as layout state. Its value gets updated during layout update.
275      * <br>
276      * This is also the value returned by getMinimumSize(),
277      * getPreferredSize(), and getMaximumSize() along
278      * the major axis if the children are not present.
279      * <br>
280      * The value does include insets.
281      * <br>
282      * <code>float</code> is chosen as the view most typically
283      * has major axes orthogonal (see isMajorAxesOrthogonal()).
284      */

285     private float lastMajorAxisPreferredSpan; // 36 + 4 = 40 bytes
286

287     /**
288      * Cached preferred span along the minor axis.
289      * <br>
290      * This is also the value returned by getMinimumSize(),
291      * getPreferredSize(), and getMaximumSize() along
292      * the major axis if the children are not present.
293      * <br>
294      * The value does include insets.
295      */

296     private float lastMinorAxisPreferredSpan; // 40 + 4 = 44 bytes
297

298     /**
299      * Current span along the minor axis as set by <code>setSize()</code>.
300      * <br>
301      * The value does include insets.
302      */

303     private float minorAxisAssignedSpan; // 44 + 4 = 48 bytes
304

305     /**
306      * Construct a composite box view over the given element.
307      *
308      * @param elem the element of the model to represent.
309      * @param majorAxis the axis to tile along. This can be
310      * either X_AXIS or Y_AXIS.
311      */

312     public GapBoxView(Element JavaDoc elem, int majorAxis) {
313         super(elem);
314
315         if (majorAxis == View.X_AXIS) {
316             setStatusBits(X_MAJOR_AXIS_BIT);
317         } // by default there should be no bits set
318
}
319
320     /**
321      * Determines the preferred span for this view along an
322      * axis.
323      *
324      * @param axis may be either View.X_AXIS or View.Y_AXIS
325      * @return the span the view would like to be rendered into &gt;= 0.
326      * Typically the view is told to render into the span
327      * that is returned, although there is no guarantee.
328      * The parent may choose to resize or break the view.
329      * @exception IllegalArgumentException for an invalid axis type
330      */

331     public float getPreferredSpan(int axis) {
332 // assert ViewUtilities.isAxisValid(axis);
333

334         return (axis == getMajorAxis())
335             ? (float)getMajorAxisPreferredSpan()
336             : getMinorAxisPreferredSpan();
337     }
338     
339     /**
340      * Determines the minimum span for this view along an
341      * axis.
342      *
343      * @param axis may be either <code>View.X_AXIS</code> or
344      * <code>View.Y_AXIS</code>
345      * @return the minimum span the view can be rendered into
346      */

347     public float getMinimumSpan(int axis) {
348         // If the following implementation gets overriden the view should
349
// consider additional caching variables because it's acting
350
// as a layout state.
351
return getPreferredSpan(axis); // getResizeWeight() not reflected
352
}
353     
354     /**
355      * Determines the maximum span for this view along an
356      * axis.
357      *
358      * @param axis may be either <code>View.X_AXIS</code> or
359      * <code>View.Y_AXIS</code>
360      * @return the maximum span the view can be rendered into
361      */

362     public float getMaximumSpan(int axis) {
363         // If the following implementation gets overriden the view should
364
// consider additional caching variables because it's acting
365
// as a layout state.
366
return getPreferredSpan(axis); // getResizeWeight() not reflected
367
}
368     
369     public float getAlignment(int axis) {
370         return 0.0f;
371     }
372
373     /**
374      * Get the insets.
375      * The default implementation here only returns null
376      * but it can be redefined by subclasses.
377      * @return insets of this view or null for no insets.
378      */

379     public ViewInsets getInsets() {
380         return null;
381     }
382
383     /**
384      * Get current preferred span along the major axis.
385      */

386     final double getMajorAxisPreferredSpan() {
387         return (children != null)
388             ? children.getMajorAxisPreferredSpan() + getMajorAxisInsetSpan()
389             : lastMajorAxisPreferredSpan; // if no children then use cached value
390
}
391     
392     final float getMinorAxisPreferredSpan() {
393         return (children != null)
394             ? children.getMinorAxisPreferredSpan() + getMinorAxisInsetSpan()
395             : lastMinorAxisPreferredSpan;
396     }
397
398     /**
399      * Get span along minor axis assigned to this view
400      * by calling <code>View.setSize()</code> on it.
401      */

402     final float getMinorAxisAssignedSpan() {
403         return minorAxisAssignedSpan;
404     }
405     
406     /**
407      * Fetch the major axis (the axis the children
408      * are tiled along). This will have a value of
409      * either X_AXIS or Y_AXIS.
410      */

411     public final int getMajorAxis() {
412         return isXMajorAxis() ? View.X_AXIS : View.Y_AXIS;
413     }
414     
415     /**
416      * Fetch the minor axis (the axis orthoginal
417      * to the tiled axis). This will have a value of
418      * either X_AXIS or Y_AXIS.
419      */

420     public final int getMinorAxis() {
421         return isXMajorAxis() ? View.Y_AXIS : View.X_AXIS;
422     }
423
424     /**
425      * Return true if X is major axis or false if Y is major axis.
426      */

427     final boolean isXMajorAxis() {
428         return isStatusBitsNonZero(X_MAJOR_AXIS_BIT);
429     }
430
431     /**
432      * Test whether the major axis of this view
433      * is orthogonal to the major axis of the layout state
434      * that this view acts like.
435      *
436      * @return true if the axes are orthogonal (which is more common case)
437      * or false if the axes are equal.
438      * <br>
439      * For example if a line view extends GapBoxView
440      * then it has X as the major axis but it has an Y layout state
441      * major axis (when acting as layout state for a document view)
442      * so this method would return true in this case.
443      */

444     final boolean isMajorAxesOrthogonal() {
445         return isStatusBitsNonZero(MAJOR_AXES_ORTHOGONAL_BIT);
446     }
447
448     /**
449      * Returns the number of child views of this view.
450      *
451      * @return the number of views &gt;= 0
452      * @see #getView(int)
453      */

454     public int getViewCount() {
455         return getChildren().getChildCount();
456     }
457     
458     /**
459      * Returns the view in this container with the particular index.
460      *
461      * @param index index of the desired view, &gt;= 0 and &lt; getViewCount()
462      * @return the view at index <code>index</code>
463      */

464     public View JavaDoc getView(int index) {
465         return getChild(index).getView();
466     }
467     
468     /*
469      * Replaces child views. If there are no views to remove
470      * this acts as an insert. If there are no views to
471      * add this acts as a remove. Views being removed will
472      * have the parent set to <code>null</code>,
473      * and the internal reference to them removed so that they
474      * may be garbage collected.
475      *
476      * <p>
477      * It is necessary to call <code>updateLayout()</code>
478      * on this view at some point later so that the possible
479      * layout changes are done.
480      *
481      * @param index the starting index into the child views >= 0
482      * @param length the number of existing views to replace >= 0
483      * @param views the child views to insert
484      */

485     public void replace(int index, int length, View JavaDoc[] views) {
486         if (length < 0) {
487             throw new IllegalArgumentException JavaDoc("length=" + length + " < 0"); // NOI18N
488
}
489         
490         if (length == 0 && (views == null || views.length == 0)) { // nothing to do
491
return;
492         }
493
494         // make sure that the children are populated
495
GapBoxViewChildren children = getChildren();
496
497         // Handle raplace in children only if either length > 0
498
// or insertLength > 0 or both are > 0
499
children.replace(index, length, views);
500     }
501
502     /**
503      * Get minimum number of children that must be added at once
504      * by replace() so that the addition is treated as a lengthy
505      * operation which means that all the added children will
506      * have the estimated span flag turned on and
507      * {@link #scheduleResetChildrenEstimatedSpan(int)}
508      * will be called to walk through the added children
509      * and reset their estimated span to false.
510      */

511     protected int getReplaceEstimatedThreshold() {
512         return Integer.MAX_VALUE;
513     }
514
515     public final boolean isEstimatedSpan() {
516         return isStatusBitsNonZero(ESTIMATED_SPAN_BIT);
517     }
518     
519     public void setEstimatedSpan(boolean estimatedSpan) {
520         if (isEstimatedSpan() != estimatedSpan) { // really changed
521
if (estimatedSpan) {
522                 setStatusBits(ESTIMATED_SPAN_BIT);
523             } else {
524                 clearStatusBits(ESTIMATED_SPAN_BIT);
525
526                 // If children exist make sure the task is scheduled to update them
527
if (children != null) {
528                     int viewCount = getViewCount();
529                     if (viewCount > 0) {
530                         resetEstimatedSpan(0, viewCount); // reset all children
531
}
532                 }
533             }
534             
535         }
536     }
537     
538     /**
539      * Set estimated span flag to false on the given children views.
540      * <br>
541      * This method is called from both <code>setEstimatedSpan()</code>
542      * and from <code>children.replace()</code> if the number of added
543      * children exceeds threshold count.
544      * <br>
545      * Subclasses may want to do this on the background.
546      */

547     protected void resetEstimatedSpan(int childIndex, int count) {
548         while (--count >= 0) {
549             ViewLayoutState child = getChild(childIndex);
550             View JavaDoc childView = child.getView();
551             if (childView instanceof EstimatedSpanView) {
552                 ((EstimatedSpanView)childView).setEstimatedSpan(false);
553             }
554             childIndex++;
555         }
556     }
557         
558     /**
559      * Remove the child views in the given index range
560      * and let the default building mechanism to build the child views.
561      *
562      * <p>
563      * It is necessary to call <code>updateLayout()</code>
564      * on this view at some point later so that the possible
565      * layout changes are done.
566      *
567      * @param index index of the first child view to be rebuilt
568      * @param count number of chilren in the children array to be rebuilt.
569      * If <code>index + count<code> is past the end of the children available
570      * the value of count will be decreased accordingly.
571      */

572     public void rebuild(int index, int count) {
573         if (count != 0) {
574             int startOffset = (index == 0) ? -1 : getView(index - 1).getEndOffset();
575             int viewCount = getViewCount();
576             int endIndex = Math.min(index + count, viewCount);
577             int endOffset = (endIndex == viewCount) ? -1 : getView(endIndex).getStartOffset();
578
579             if (debugRebuild) {
580                 /*DEBUG*/System.err.println("GapBoxView.rebuild(): index=" + index // NOI18N
581
+ ", count=" + count // NOI18N
582
+ ", so=" + startOffset + ", eo=" + endOffset // NOI18N
583
);
584             }
585
586             reloadChildren(index, count, startOffset, endOffset);
587         }
588     }
589     
590     /**
591      * Rebuild based on specification of the offset range.
592      *
593      * @param startOffset starting offset of the area in which the views
594      * should be rebuilt.
595      * @param endOffset ending offset of the area in which the views
596      * should be rebuilt.
597      */

598     public void offsetRebuild(int startOffset, int endOffset) {
599         int index = ViewUtilitiesImpl.findLowerViewIndex(this, startOffset, false);
600         int count;
601         if (index == -1) { // no child views
602
index = 0;
603             count = 0;
604             
605         } else { // child views exist
606
count = ViewUtilitiesImpl.findUpperViewIndex(this, endOffset, true) - index + 1;
607         }
608         
609         rebuild(index, count);
610     }
611     
612     /**
613      * Sets the parent of the view.
614      * The children are only initialized if someone
615      * has previously asked for information
616      * related to children (e.g. <code>getViewCount()</code>)
617      * or for preferred, minimum or maximum span of this view.
618      *
619      * @param parent the parent of the view, <code>null</code> if none
620      */

621     public void setParent(View JavaDoc parent) {
622         super.setParent(parent);
623         
624         /* Make sure that the children get loaded.
625          * It is necessary to do because children preferences will
626          * define the preferences of the parent.
627          */

628         if (parent != null) {
629             if (parent instanceof ViewLayoutState.Parent) {
630                 setStatusBits(ACTIVE_LAYOUT_STATE);
631             } else {
632                 clearStatusBits(ACTIVE_LAYOUT_STATE);
633             }
634             
635             // Resolving whether active layout state must be resolved prior getChildren()
636
getChildren();
637             
638         } else { // parent is being set to null
639
releaseChildren();
640             clearStatusBits(ACTIVE_LAYOUT_STATE);
641         }
642     }
643     
644     public final boolean isActiveLayoutState() {
645         return isStatusBitsNonZero(ACTIVE_LAYOUT_STATE);
646     }
647
648     protected GapBoxViewChildren getChildren() {
649         if (children == null) {
650             children = createChildren();
651
652             // Possibly load the children
653
View JavaDoc parent = getParent();
654             if (parent != null) { // initialize with valid view factory only
655
reloadChildren(0, 0, -1, -1);
656             }
657         }
658         
659         return children;
660     }
661     
662     /**
663      * Get children or null if the children were not yet initialized.
664      */

665     protected final GapBoxViewChildren getChildrenNull() {
666         return children;
667     }
668
669     /**
670      * Ask for releasing of the children.
671      * The view will still remember the last allocated size
672      * and preferred, minimum and maximum spans.
673      * However various operations like painting or translations
674      * between model and visual positions will
675      * make the children to be loaded again.
676      */

677     public void releaseChildren() {
678         if (children != null) {
679             unloadChildren();
680
681             children.unload();
682             children = null;
683         }
684     }
685
686     // Implements ViewLayoutState
687
public final View JavaDoc getView() {
688         return this;
689     }
690     
691     // Implements ViewLayoutState
692
public ViewLayoutState selectLayoutMajorAxis(int axis) {
693 // assert ViewUtilities.isAxisValid(axis);
694

695         if (axis == View.X_AXIS) {
696             setStatusBits(LAYOUT_STATE_X_MAJOR_AXIS_BIT);
697         } else { // y as layout major axis
698
clearStatusBits(LAYOUT_STATE_X_MAJOR_AXIS_BIT);
699         }
700         
701         // Determine whether major axis of this view
702
// is orthogonal to major axis for acting as layout state
703
if (axis == getMajorAxis()) { // major axes equal
704
clearStatusBits(MAJOR_AXES_ORTHOGONAL_BIT);
705         } else { // major axes orthogonal
706
setStatusBits(MAJOR_AXES_ORTHOGONAL_BIT);
707         }
708         
709         return this;
710     }
711     
712     // Implements ViewLayoutState
713
public boolean isFlyweight() {
714         return false;
715     }
716     
717     // Implements ViewLayoutState
718
public void updateLayout() {
719         if (isLayoutValid()) { // Nothing to do
720
return;
721         }
722         
723         if (isStatusBitsNonZero(UPDATE_LAYOUT_IN_PROGRESS)) {
724             return;
725         }
726         setStatusBits(UPDATE_LAYOUT_IN_PROGRESS);
727
728         View JavaDoc parent = getParent();
729         if (parent == null) { // disconnected from hierarchy
730
return;
731         }
732         ViewLayoutState.Parent lsParent = (parent instanceof ViewLayoutState.Parent)
733             ? (ViewLayoutState.Parent)parent
734             : null;
735
736         // Make sure all individual pending children layout updates are addressed
737
children.childrenUpdateLayout();
738
739         // Layout the children if necessary
740
if (isChildrenLayoutNecessary()) {
741             resetChildrenLayoutNecessary();
742
743             children.childrenLayout(); // re-compute layout info for children
744
}
745
746         // Update cached variable corresponding to layout state major axis
747
boolean parentWillRepaint = false;
748
749         // Check whether preference did not change along a particular axis
750
// and if so message preferenceChanged to parent.
751
// Cache the following two vars before they get cleared in next section:
752
boolean majorAxisPreferenceChanged = isMajorAxisPreferenceChanged();
753         boolean minorAxisPreferenceChanged = isMinorAxisPreferenceChanged();
754         resetAxesPreferenceChanged();
755
756         if (majorAxisPreferenceChanged) {
757             // Update the cached value for the major axis
758
if (children != null) { // only if children exist
759
double delta = updateLastMajorAxisPreferredSpan();
760                 if (delta != 0.0d && lsParent != null) {
761                     if (isMajorAxesOrthogonal()) {
762                         lsParent.minorAxisPreferenceChanged(this);
763                     } else {
764                         lsParent.majorAxisPreferenceChanged(this, delta);
765                         parentWillRepaint = true;
766                     }
767                 }
768             }
769         }
770
771         if (minorAxisPreferenceChanged) {
772             // Update the cached value for the minor axis
773
if (children != null) { // only if children exist
774
double delta = updateLastMinorAxisPreferredSpan();
775                 if (delta != 0.0d && lsParent != null) {
776                     if (isMajorAxesOrthogonal()) {
777                         lsParent.majorAxisPreferenceChanged(this, delta);
778                         parentWillRepaint = true;
779                     } else {
780                         lsParent.minorAxisPreferenceChanged(this);
781                     }
782                 }
783             }
784         }
785
786         // If not active layout state propagate preference change upwards
787
// If this is active layout state then this was already propagated
788
// by marking itself as needing layout update which is now being
789
// updated.
790
if (majorAxisPreferenceChanged || minorAxisPreferenceChanged || !isActiveLayoutState()) {
791             // Either of major or minor axis (or both) has changed
792
boolean horizontalChange = false;
793             boolean verticalChange = false;
794
795             if (isXMajorAxis()) {
796                 horizontalChange = majorAxisPreferenceChanged;
797                 verticalChange = minorAxisPreferenceChanged;
798             } else {
799                 horizontalChange = minorAxisPreferenceChanged;
800                 verticalChange = majorAxisPreferenceChanged;
801             }
802
803             parent.preferenceChanged(this, horizontalChange, verticalChange);
804         }
805
806         // Check whether size must be set on this view
807
if (isStatusBitsNonZero(LAYOUT_STATE_VIEW_SIZE_INVALID_BIT)) {
808             clearStatusBits(LAYOUT_STATE_VIEW_SIZE_INVALID_BIT);
809
810             if (lsParent != null) { // should only be done when having layout state parent
811
float width;
812                 float height;
813                 float layoutStateMajorAxisSpan = getPreferredSpan(getLayoutStateMajorAxis());
814                 float layoutStateMinorAxisSpan = lsParent.getMinorAxisSpan(this);
815                 if (isXLayoutStateMajorAxis()) {
816                     width = layoutStateMajorAxisSpan;
817                     height = layoutStateMinorAxisSpan;
818                 } else {
819                     width = layoutStateMinorAxisSpan;
820                     height = layoutStateMajorAxisSpan;
821                 }
822
823                 setSize(width, height);
824             }
825         }
826         
827         if (children != null && isRepaintPending()) {
828             if (!parentWillRepaint) {
829                 processRepaint(lsParent);
830             }
831             // After painting is finished reset the variables
832
resetRepaintPending();
833         }
834         
835         clearStatusBits(UPDATE_LAYOUT_IN_PROGRESS);
836         
837         // Call recursively to make sure that there is no more work.
838
updateLayout();
839     }
840     
841     /**
842      * Update the layout in response to receiving notification of
843      * change from the model.
844      *
845      * @param ec changes to the element this view is responsible
846      * for (may be null if there were no changes).
847      * @param e the change information from the associated document
848      * @param a the current allocation of the view
849      * @see #insertUpdate
850      * @see #removeUpdate
851      * @see #changedUpdate
852      */

853     protected void updateLayout(DocumentEvent.ElementChange JavaDoc ec,
854     DocumentEvent JavaDoc e, Shape JavaDoc a) {
855         
856         //super.updateLayout(ec, e, a);
857
}
858
859     /**
860      * Called by children to mark layout of this view invalid.
861      * This only has effect if this view is active layout state.
862      */

863     public void layoutInvalid(ViewLayoutState child) {
864         int childIndex = children.getChildIndexNoCheck(child);
865         children.markLayoutInvalid(childIndex, 1);
866     }
867     
868     protected void markLayoutInvalid() {
869         if (isActiveLayoutState()) {
870             ((ViewLayoutState.Parent)getParent()).layoutInvalid(this);
871         } else { // not active layout state
872
// Update layout immediately - subclasses can override
873
directUpdateLayout();
874         }
875     }
876     
877     /**
878      * This method is called when this view is not acting as active
879      * layout state and its layout becomes invalid.
880      * <br>
881      * By default the layout is updated immediately
882      * but subclasses may change that but they must ensure
883      * that the layout will be updated later.
884      */

885     protected void directUpdateLayout() {
886         updateLayout();
887     }
888     
889     /**
890      * Process pending repaint requests from children.
891      * <br>
892      * Children are guaranteed to be non-null once this method gets called.
893      */

894     protected void processRepaint(ViewLayoutState.Parent lsParent) {
895         if (lsParent != null) { // parent view is ViewLayoutState.Parent
896
int firstRepaintChildIndex = children.getFirstRepaintChildIndex();
897             double majorAxisOffset = children.getMajorAxisOffset(firstRepaintChildIndex);
898             double repaintMajorOffset;
899             double repaintMajorSpan;
900             float repaintMinorOffset;
901             float repaintMinorSpan;
902             if (isRepaintTillEnd()
903                 || firstRepaintChildIndex >= getViewCount() // bit strange but possible after last child remove
904
) {
905                 if (isMajorAxesOrthogonal()) {
906                     repaintMajorOffset = 0;
907                     repaintMajorSpan = 0; // till end of view's span in parent
908
repaintMinorOffset = (float)majorAxisOffset;
909                     repaintMinorSpan = 0; // till parent view minor span end
910

911                 } else { // major axes equal
912
repaintMajorOffset = majorAxisOffset;
913                     repaintMajorSpan = 0; // till end of view's span in parent
914
repaintMinorOffset = 0;
915                     repaintMinorSpan = 0; // till parent view minor span end
916
}
917
918             } else { // repainting just single child that did not change major axis span
919
double majorAxisSpan = getChild(firstRepaintChildIndex).getLayoutMajorAxisPreferredSpan();
920                 if (isMajorAxesOrthogonal()) {
921                     repaintMajorOffset = 0;
922                     repaintMajorSpan = 0; // till end of view's span in parent
923
repaintMinorOffset = (float)majorAxisOffset;
924                     repaintMinorSpan = (float)majorAxisSpan;
925
926                 } else { // major axes equal
927
repaintMajorOffset = majorAxisOffset;
928                     repaintMajorSpan = majorAxisSpan;
929                     repaintMinorOffset = 0;
930                     repaintMinorSpan = 0; // till parent view minor span end
931
}
932             }
933             
934             lsParent.repaint(this, repaintMajorOffset, repaintMajorSpan,
935                 repaintMinorOffset, repaintMinorSpan);
936             
937         } else { // do not know allocation here => repaint whole component
938
Component JavaDoc c = getContainer();
939             if (c != null) {
940                 c.repaint();
941             }
942         }
943     }
944
945     /**
946      * Mark that the child with the given index should be repainted.
947      *
948      * @param childIndex index of child that should be marked for repaint.
949      * @param repaintTillEnd if set to true then all children following
950      * the child should be repainted as well.
951      * @return true if lower child index was marked for repaint by this method
952      * than there was before.
953      */

954     protected boolean markRepaint(int childIndex, boolean repaintTillEnd) {
955         boolean lowerIndexMarked = false;
956         if (children != null) {
957             int firstRepaintChildIndex = children.getFirstRepaintChildIndex();
958             if (!isRepaintTillEnd()) { // not repainting more yet
959
if (firstRepaintChildIndex == -1) { // no repainting yet
960
lowerIndexMarked = true;
961                     markRepaintPending();
962                     children.setFirstRepaintChildIndex(childIndex);
963                     if (repaintTillEnd) {
964                         setStatusBits(REPAINT_TILL_END_BIT);
965                     }
966
967                 } else if (firstRepaintChildIndex != childIndex) { // other child than first
968
if (childIndex < firstRepaintChildIndex) {
969                         lowerIndexMarked = true;
970                         children.setFirstRepaintChildIndex(childIndex);
971                     }
972                     setStatusBits(REPAINT_TILL_END_BIT); // surely will repaint to end
973

974                 } else { // same child already scheduled for repaint
975
if (repaintTillEnd) {
976                         setStatusBits(REPAINT_TILL_END_BIT);
977                     }
978                 }
979
980             } else { // repaint more children already - firstRepaintChildIndex must be valid
981
if (childIndex < firstRepaintChildIndex) {
982                     lowerIndexMarked = true;
983                     children.setFirstRepaintChildIndex(childIndex);
984                 }
985             }
986         }
987         
988         return lowerIndexMarked;
989     }
990     
991     public final boolean isRepaintPending() {
992         return isStatusBitsNonZero(REPAINT_PENDING_BIT);
993     }
994     
995     protected final void markRepaintPending() {
996         setStatusBits(REPAINT_PENDING_BIT);
997     }
998     
999     protected void resetRepaintPending() {
1000        if (children != null) {
1001            children.setFirstRepaintChildIndex(-1);
1002        }
1003        clearStatusBits(REPAINT_PENDING_BIT | REPAINT_TILL_END_BIT);
1004    }
1005    
1006    public final boolean isRepaintTillEnd() {
1007        return isStatusBitsNonZero(REPAINT_TILL_END_BIT);
1008    }
1009    
1010    /**
1011     * Test whether the preference along the layout state minor axis
1012     * has really changed.
1013     * <br>
1014     * The default implementation only checks preferred span
1015     * but the implementation reflecting minimum and maximum spans
1016     * can extend this method.
1017     *
1018     * @return true if it has really changed or false if not.
1019     */

1020    protected boolean isLayoutMinorAxisPreferenceChanged(boolean majorAxesOrthogonal) {
1021        double delta;
1022        if (majorAxesOrthogonal) {
1023            // processing minor layout state axis but it's in fact major view axis
1024
delta = updateLastMajorAxisPreferredSpan();
1025        } else { // major axes equal
1026
// processing minor layout state axis which is also minor view axis
1027
delta = updateLastMinorAxisPreferredSpan();
1028        }
1029        
1030        return (delta != 0.0d);
1031    }
1032
1033    private double updateLastMinorAxisPreferredSpan() {
1034        float currentMinorAxisPreferredSpan = children.getMinorAxisPreferredSpan();
1035        double delta = currentMinorAxisPreferredSpan - lastMinorAxisPreferredSpan;
1036        lastMinorAxisPreferredSpan = currentMinorAxisPreferredSpan;
1037        return delta;
1038    }
1039    
1040    private double updateLastMajorAxisPreferredSpan() {
1041        double currentMajorAxisPreferredSpan = children.getMajorAxisPreferredSpan();
1042        double delta = currentMajorAxisPreferredSpan - lastMajorAxisPreferredSpan;
1043        // Here the truncation occurs but if the major axes are orthogonal
1044
// or if the spans are not big enough to exhaust float precision
1045
// this should not hurt.
1046
lastMajorAxisPreferredSpan = (float)currentMajorAxisPreferredSpan;
1047        return delta;
1048    }
1049    
1050    // Implements ViewLayoutState
1051
public boolean isLayoutValid() {
1052        return !isStatusBitsNonZero(LAYOUT_STATE_ANY_INVALID)
1053            && (children == null || children.getUpdateLayoutChildCount() == 0);
1054    }
1055
1056    // Implements ViewLayoutState
1057
public double getLayoutMajorAxisPreferredSpan() {
1058        return (isMajorAxesOrthogonal())
1059            ? lastMinorAxisPreferredSpan
1060            : lastMajorAxisPreferredSpan;
1061    }
1062    
1063    // Implements ViewLayoutState
1064
public float getLayoutMinorAxisPreferredSpan() {
1065        return isMajorAxesOrthogonal()
1066            ? lastMajorAxisPreferredSpan
1067            : lastMinorAxisPreferredSpan;
1068    }
1069
1070    // Implements ViewLayoutState
1071
public float getLayoutMinorAxisMinimumSpan() {
1072        // It has to be overriden if the layout state minimum span is maintained
1073
return getLayoutMinorAxisPreferredSpan();
1074    }
1075
1076    // Implements ViewLayoutState
1077
public float getLayoutMinorAxisMaximumSpan() {
1078        // It has to be overriden if the layout state maximum span is maintained
1079
return getLayoutMinorAxisPreferredSpan();
1080    }
1081    
1082    // Implements ViewLayoutState
1083
public float getLayoutMinorAxisAlignment() {
1084        // Alignment is assumed not to change over time
1085
// It needs to be cached if that's not true
1086
return getAlignment(getLayoutStateMinorAxis());
1087    }
1088    
1089    // Implements ViewLayoutState
1090
public double getLayoutMajorAxisRawOffset() {
1091        return layoutStateMajorAxisRawOffset;
1092    }
1093    
1094    // Implements ViewLayoutState
1095
public void setLayoutMajorAxisRawOffset(double majorAxisRawOffset) {
1096        this.layoutStateMajorAxisRawOffset = majorAxisRawOffset;
1097    }
1098    
1099    protected final ViewLayoutState.Parent getLayoutStateParent() {
1100        View JavaDoc parent = getParent();
1101        return (parent instanceof ViewLayoutState.Parent)
1102            ? ((ViewLayoutState.Parent)parent)
1103            : null;
1104    }
1105
1106    protected final boolean isXLayoutStateMajorAxis() {
1107        return (isStatusBitsNonZero(LAYOUT_STATE_X_MAJOR_AXIS_BIT));
1108    }
1109    
1110    protected final int getLayoutStateMajorAxis() {
1111        return (isStatusBitsNonZero(LAYOUT_STATE_X_MAJOR_AXIS_BIT))
1112            ? View.X_AXIS
1113            : View.Y_AXIS;
1114    }
1115
1116    protected final int getLayoutStateMinorAxis() {
1117        return (isStatusBitsNonZero(LAYOUT_STATE_X_MAJOR_AXIS_BIT))
1118            ? View.Y_AXIS
1119            : View.X_AXIS;
1120    }
1121    
1122    // Implements ViewLayoutState
1123
public int getViewRawIndex() {
1124        return viewRawIndex;
1125    }
1126    
1127    // Implements ViewLayoutState
1128
public void setViewRawIndex(int viewRawIndex) {
1129        this.viewRawIndex = viewRawIndex;
1130    }
1131
1132    // Implements ViewLayoutState
1133
public void viewPreferenceChanged(boolean width, boolean height) {
1134        markViewSizeInvalid();
1135    }
1136    
1137    // Implements ViewLayoutState
1138
public void markViewSizeInvalid() {
1139        setStatusBits(LAYOUT_STATE_VIEW_SIZE_INVALID_BIT);
1140    }
1141
1142    // Implements ViewLayoutState.Parent
1143
/**
1144     * Preference of one of the children has changed along the major axis.
1145     */

1146    public void majorAxisPreferenceChanged(ViewLayoutState child, double majorAxisSpanDelta) {
1147        int childIndex = getChildIndexNoCheck(child);
1148        if (majorAxisSpanDelta != 0.0d) {
1149            // repaint till end as the children above the index get shifted
1150
markRepaint(childIndex, true);
1151            children.majorAxisPreferenceChanged(child, childIndex, majorAxisSpanDelta);
1152
1153        } else { // make sure that the child gets repainted
1154
markRepaint(childIndex, false);
1155        }
1156    }
1157
1158    // Implements ViewLayoutState.Parent
1159
/**
1160     * Preference of one of the children has changed along the minor axis.
1161     */

1162    public void minorAxisPreferenceChanged(ViewLayoutState child) {
1163        int childIndex = getChildIndexNoCheck(child);
1164        markRepaint(childIndex, false);
1165        children.minorAxisPreferenceChanged(child, childIndex);
1166    }
1167    
1168    // Implements ViewLayoutState.Parent
1169
/**
1170     * Get span of the given child along the minor axis of this view.
1171     */

1172    public float getMinorAxisSpan(ViewLayoutState child) {
1173        // Delegate to children
1174
return getChildren().getMinorAxisSpan(child);
1175    }
1176    
1177    // Implements ViewLayoutState.Parent
1178
public void repaint(ViewLayoutState child,
1179    double majorAxisOffset, double majorAxisSpan,
1180    float minorAxisOffset, float minorAxisSpan) {
1181
1182        int childIndex = getChildIndexNoCheck(child);
1183        markRepaint(childIndex, false);
1184    }
1185
1186    /**
1187     * Test whether complete layout of the children necessary.
1188     */

1189    public final boolean isChildrenLayoutNecessary() {
1190        return isStatusBitsNonZero(CHILDREN_LAYOUT_NECESSARY_BIT);
1191    }
1192    
1193    /**
1194     * Mark that a complete layout of children is necessary.
1195     * <br>
1196     * This method does no scheduling of the children layout update.
1197     */

1198    public final void markChildrenLayoutNecessary() {
1199        setStatusBits(CHILDREN_LAYOUT_NECESSARY_BIT);
1200    }
1201    
1202    final void resetChildrenLayoutNecessary() {
1203        clearStatusBits(CHILDREN_LAYOUT_NECESSARY_BIT);
1204    }
1205
1206    /**
1207     * Child views can call this on the parent to indicate that
1208     * the preference has changed and should be reconsidered
1209     * for layout. This is reimplemented to queue new work
1210     * on the layout thread. This method gets messaged from
1211     * multiple threads via the children.
1212     *
1213     * @param childView the child view of this view or null to signal
1214     * change in this view.
1215     * @param width true if the width preference has changed
1216     * @param height true if the height preference has changed
1217     * @see javax.swing.JComponent#revalidate
1218     */

1219    public void preferenceChanged(View JavaDoc childView, boolean width, boolean height) {
1220        if (childView == null) { // notify parent about this view change
1221
getParent().preferenceChanged(this, width, height);
1222
1223        } else { // Child of this view has changed
1224
// First find the index of the child view
1225
int index;
1226            // Try to cast the view to ViewLayoutState and find index that way
1227
if (childView instanceof ViewLayoutState) {
1228                // Trust the view to be really child of this view - check is done later
1229
index = getChildIndexNoCheck((ViewLayoutState)childView);
1230            } else { // child view not instance of ViewLayoutState
1231
// Use binary search to find the view
1232
index = getViewIndex(childView.getStartOffset());
1233            }
1234
1235            ViewLayoutState child = getChild(index);
1236            if (child.getView() != childView) {
1237                int ind;
1238                for (ind = getViewCount() - 1; ind >= 0; ind--) {
1239                    if (getView(ind) == childView) {
1240                        break;
1241                    }
1242                }
1243                if (ind == -1) {
1244                    throw new IllegalArgumentException JavaDoc("childView=" // NOI18N
1245
+ childView + " not child of view " + this); // NOI18N
1246

1247                } else { // is child but at different index
1248
throw new IllegalStateException JavaDoc(
1249                        "Internal error. Child expected at index=" + index // NOI18N
1250
+ " but found at index=" + ind); // NOI18N
1251
}
1252            }
1253
1254            // Mark the child as invalid
1255
child.viewPreferenceChanged(width, height);
1256
1257            // Mark the layout of the child as invalid - this must be done
1258
// _after_ the real changes affecting child's layout were performed
1259
// because the layout may be directly updated
1260
// by the parent during the call of the following method.
1261
children.markLayoutInvalid(index, 1);
1262        }
1263    }
1264    
1265    /**
1266     * Sets the size of the view. This should cause
1267     * layout of the view if the view caches any layout
1268     * information.
1269     *
1270     * <p>
1271     * The propagation of this operation to child views
1272     * can be done asynchronously if appropriate.
1273     *
1274     * @param width the width &gt;= 0
1275     * @param height the height &gt;= 0
1276     */

1277    public void setSize(float width, float height) {
1278        float targetMajorAxisSpan;
1279        float targetMinorAxisSpan;
1280        if (isXMajorAxis()) {
1281            targetMajorAxisSpan = width;
1282            targetMinorAxisSpan = height;
1283        } else { // Y is major axis
1284
targetMajorAxisSpan = height;
1285            targetMinorAxisSpan = width;
1286        }
1287        
1288        // Span along major axis is ignored by default
1289
setSpanOnMajorAxis(targetMajorAxisSpan);
1290        setSpanOnMinorAxis(targetMinorAxisSpan);
1291    }
1292    
1293    protected void setSpanOnMajorAxis(float targetMajorAxisSpan) {
1294        // along the major axis the value is ignored by default
1295
// but subclasses doing e.g. line wrapping can override that
1296
}
1297    
1298    protected void setSpanOnMinorAxis(float targetMinorAxisSpan) {
1299        if (targetMinorAxisSpan != minorAxisAssignedSpan) {
1300            minorAxisAssignedSpan = targetMinorAxisSpan;
1301            //float targetSpanNoInsets = targetMinorAxisSpan - getMinorAxisInsetSpan();
1302

1303            // do not recompute children if estimated span or estimated change task running
1304
if (!isEstimatedSpan() && !isChildrenResizeDisabled()) {
1305                // mark all of the ViewLayoutState instances as needing to
1306
// resize the child.
1307
int viewCount = getViewCount();
1308                if (viewCount != 0) {
1309                    markSizeInvalid(0, viewCount);
1310                }
1311            }
1312        }
1313    }
1314
1315    /**
1316     * This method marks sizes of all the children as invalid
1317     * so the next layout update will resize each children.
1318     * <br>
1319     * This is made as protected method since large complex views
1320     * may consider this operation lengthy with certain amount
1321     * of children so they may need to do this operation in background
1322     * and delegate to this implementation for small amount
1323     * of children only.
1324     *
1325     * @param &gt;0 total number of child views of this view. It's given
1326     * as parameter because subclasses will typically decide their
1327     * behavior based on the total view count.
1328     */

1329    protected void markSizeInvalid(int childIndex, int count) {
1330        while (--count >= 0) {
1331            ViewLayoutState child = getChild(childIndex);
1332            if (!child.isFlyweight()) {
1333                child.markViewSizeInvalid();
1334            }
1335            childIndex++;
1336        }
1337
1338        // Mark the layout of the child as invalid - this must be done
1339
// _after_ the real changes affecting child's layout were performed
1340
// because the layout may be directly updated
1341
// by the parent during the call of the following method.
1342
children.markLayoutInvalid(childIndex, count);
1343    }
1344
1345    /**
1346     * Return true if the children should not be attempted to resize
1347     * once <code>setSize()</code> is called on this view.
1348     * <br>
1349     * Turning this on may save considerable time but it should be only
1350     * used if the views truly do not react on <code>setSize()</code>
1351     * e.g. this should *not* be used if line-wrapping is turned on.
1352     */

1353    protected boolean isChildrenResizeDisabled() {
1354        return false; // by default must resize children upon setSize() on view
1355
}
1356    
1357    /**
1358     * Fetches the allocation for the given child view.
1359     * This enables finding out where various views
1360     * are located, without assuming the views store
1361     * their location. This returns null since the
1362     * default is to not have any child views.
1363     *
1364     * @param index the index of the child, &gt;= 0 and &lt; getViewCount()
1365     * @param a the allocation to this view.
1366     * @return the allocation to the child
1367     */

1368    public Shape JavaDoc getChildAllocation(int index, Shape JavaDoc a) {
1369        if (a == null) {
1370            return null;
1371        }
1372
1373        Rectangle JavaDoc alloc = reallocate(a); // returned rect can be modified
1374
int thisViewAllocX = alloc.x;
1375        int thisViewAllocY = alloc.y;
1376
1377        getChildren().getChildCoreAllocation(index, alloc); // alloc overwritten
1378
alloc.x += thisViewAllocX;
1379        alloc.y += thisViewAllocY;
1380        
1381        // Add insets if necessary
1382
ViewInsets insets = getInsets();
1383        if (insets != null) {
1384            alloc.x += insets.getLeft();
1385            alloc.y += insets.getRight();
1386        }
1387
1388        return alloc;
1389    }
1390    
1391    /**
1392     * Fetches the child view index at the given point.
1393     * This is called by the various View methods that
1394     * need to calculate which child to forward a message
1395     * to.
1396     *
1397     * @param x the X coordinate &gt;= 0
1398     * @param y the Y coordinate &gt;= 0
1399     * @param a the allocation to thid view
1400     * @return index of the view that best represents the given visual
1401     * location or -1 if there are no children.
1402     * <br>
1403     * If the point is below the area of the first child view
1404     * then the index of the first child view is returned.
1405     * <br>
1406     * If the point is above the area of the last child view
1407     * then the index of the last child view is returned.
1408     */

1409    public int getViewIndexAtPoint(float x, float y, Shape JavaDoc a) {
1410        Rectangle JavaDoc alloc = reallocate(a); // returned rect can be modified
1411
x -= alloc.x;
1412        y -= alloc.y;
1413
1414        // Subtract insets if necessary
1415
ViewInsets insets = getInsets();
1416        if (insets != null) {
1417            x -= insets.getLeft();
1418            y -= insets.getRight();
1419        }
1420
1421        return getChildren().getChildIndexAtCorePoint(x, y);
1422    }
1423    
1424    /**
1425     * Returns the child view index representing the given position in
1426     * the model.
1427     *
1428     * @param offset the position >= 0.
1429     * @param b either forward or backward bias.
1430     * @return index of the view representing the given position, or
1431     * -1 if no view represents that position
1432     */

1433    public int getViewIndex(int offset, Position.Bias JavaDoc b) {
1434    if (b == Position.Bias.Backward) {
1435        offset -= 1;
1436    }
1437        
1438        return getViewIndex(offset);
1439    }
1440    
1441    /**
1442     * Returns the child view index representing the given position in
1443     * the model.
1444     *
1445     * @param offset the position >= 0.
1446     * @return index of the view representing the given position, or
1447     * -1 if no view represents that position
1448     */

1449    public int getViewIndex(int offset) {
1450        return ViewUtilitiesImpl.findViewIndexBounded(this, offset);
1451    }
1452
1453    /**
1454     * Render the view using the given allocation and
1455     * rendering surface.
1456     *
1457     * @param g the rendering surface to use
1458     * @param a the allocated region to render into
1459     * @see View#paint
1460     */

1461    public void paint(Graphics JavaDoc g, Shape JavaDoc a) {
1462        Rectangle JavaDoc alloc = reallocate(a); // returned rect can be modified
1463
getChildren().paintChildren(g, alloc);
1464    }
1465    
1466    /**
1467     * Provides a mapping from the document model coordinate space
1468     * to the coordinate space of the view mapped to it.
1469     *
1470     * @param pos the position to convert &gt;= 0
1471     * @param a the allocated region to render into
1472     * @param b the bias toward the previous character or the
1473     * next character represented by the offset, in case the
1474     * position is a boundary of two views.
1475     * @return the bounding box of the given position is returned
1476     * @exception BadLocationException if the given position does
1477     * not represent a valid location in the associated document
1478     * @exception IllegalArgumentException for an invalid bias argument
1479     * @see View#viewToModel
1480     */

1481    public Shape JavaDoc modelToView(int pos, Shape JavaDoc a, Position.Bias JavaDoc b) throws BadLocationException JavaDoc {
1482        int index = getViewIndex(pos, b);
1483        Shape JavaDoc ret;
1484        if (index >= 0) {
1485            Shape JavaDoc ca = getChildAllocation(index, a);
1486
1487            // forward to the child view
1488
ViewLayoutState child = getChild(index);
1489            View JavaDoc cv = child.getView();
1490            ret = cv.modelToView(pos, ca, b);
1491 
1492        } else {
1493            ret = null;
1494        }
1495
1496        return ret;
1497    }
1498    
1499    /**
1500     * Provides a mapping from the view coordinate space to the logical
1501     * coordinate space of the model. The biasReturn argument will be
1502     * filled in to indicate that the point given is closer to the next
1503     * character in the model or the previous character in the model.
1504     * <p>
1505     * This is expected to be called by the GUI thread, holding a
1506     * read-lock on the associated model. It is implemented to
1507     * locate the child view and determine it's allocation with a
1508     * lock on the ChildLocator object, and to call viewToModel
1509     * on the child view with a lock on the ViewLayoutState object
1510     * to avoid interaction with the layout thread.
1511     *
1512     * @param x the X coordinate &gt;= 0
1513     * @param y the Y coordinate &gt;= 0
1514     * @param a the allocated region to render into
1515     * @return the location within the model that best represents the
1516     * given point in the view &gt;= 0. The biasReturn argument will be
1517     * filled in to indicate that the point given is closer to the next
1518     * character in the model or the previous character in the model.
1519     */

1520    public int viewToModel(float x, float y, Shape JavaDoc a, Position.Bias JavaDoc[] biasReturn) {
1521        int pos; // return position
1522
int index; // child index to forward to
1523
Shape JavaDoc ca; // child allocation
1524

1525        index = getViewIndexAtPoint(x, y, a);
1526        index = Math.max(index, 0);
1527        if (index < getViewCount()) {
1528            ca = getChildAllocation(index, a);
1529
1530            // forward to the child view
1531
ViewLayoutState child = getChild(index);
1532            View JavaDoc v = child.getView();
1533            pos = v.viewToModel(x, y, ca, biasReturn);
1534
1535        } else { // at the end
1536
int endOff = getEndOffset();
1537            Document JavaDoc doc = getDocument();
1538            pos = (doc!=null && doc.getLength() < endOff) ? doc.getLength() : endOff;
1539        }
1540
1541        return pos;
1542    }
1543    
1544    /**
1545     * Provides a way to determine the next visually represented model
1546     * location that one might place a caret. Some views may not be visible,
1547     * they might not be in the same order found in the model, or they just
1548     * might not allow access to some of the locations in the model.
1549     *
1550     * @param pos the position to convert &gt;= 0
1551     * @param a the allocated region to render into
1552     * @param direction the direction from the current position that can
1553     * be thought of as the arrow keys typically found on a keyboard;
1554     * this may be one of the following:
1555     * <ul>
1556     * <code>SwingConstants.WEST</code>
1557     * <code>SwingConstants.EAST</code>
1558     * <code>SwingConstants.NORTH</code>
1559     * <code>SwingConstants.SOUTH</code>
1560     * </ul>
1561     * @param biasRet an array contain the bias that was checked
1562     * @return the location within the model that best represents the next
1563     * location visual position
1564     * @exception BadLocationException
1565     * @exception IllegalArgumentException if <code>direction</code> is invalid
1566     */

1567    public int getNextVisualPositionFrom(int pos, Position.Bias JavaDoc b, Shape JavaDoc a,
1568    int direction, Position.Bias JavaDoc[] biasRet) throws BadLocationException JavaDoc {
1569
1570        return ViewUtilitiesImpl.getNextVisualPositionFrom(
1571            this, pos, b, a, direction, biasRet);
1572    }
1573
1574    /**
1575     * Fetch the object representing the layout state of
1576     * of the child at the given index.
1577     *
1578     * @param index the child index.
1579     * This must be a value &gt;= 0 and &lt; getViewCount().
1580     * @throws IndexOutOfBoundsException in case the index was invalid.
1581     */

1582    protected final ViewLayoutState getChild(int index) {
1583        return getChildren().getChild(index);
1584    }
1585    
1586    /**
1587     * Get the index of the given child layout state in this view.
1588     *
1589     * @param child layout state which index in this view should be found.
1590     * @return &gt;=0 integer index of the given child in this view.
1591     * Returns -1 if the given child is not present at the given index
1592     * in this view.
1593     */

1594    protected final int getChildIndex(ViewLayoutState child) {
1595        return getChildren().getChildIndex(child);
1596    }
1597    
1598    /**
1599     * Get the index of the given child layout state in this view.
1600     *
1601     * @param child layout state which index in this view should be found.
1602     * @return &gt;=0 integer index of the given child in this view.
1603     * <b>Note:</b> This method does no checking whether the child
1604     * is really the child of this view.
1605     */

1606    protected final int getChildIndexNoCheck(ViewLayoutState child) {
1607        return getChildren().getChildIndexNoCheck(child);
1608    }
1609
1610    /**
1611     * Can be overriden by subclasses to return
1612     * a different children implementation.
1613     */

1614    protected GapBoxViewChildren createChildren() {
1615        return new GapBoxViewChildren(this);
1616    }
1617
1618    protected boolean useCustomReloadChildren() {
1619        return (getElement() == null);
1620    }
1621    
1622    public void insertUpdate(DocumentEvent JavaDoc evt, Shape JavaDoc a, ViewFactory JavaDoc f) {
1623        // #38993 - until parent is set - do not do anything
1624
if (children == null && getParent() == null) {
1625            return;
1626        }
1627
1628        if (useCustomReloadChildren()) {
1629            customInsertUpdate(evt, a, f);
1630        } else { // custom insert update
1631
super.insertUpdate(evt, a, f); // default element-based update
1632
}
1633    }
1634
1635    protected void customInsertUpdate(DocumentEvent JavaDoc evt, Shape JavaDoc a, ViewFactory JavaDoc f) {
1636        int[] offsetRange = getInsertUpdateRebuildOffsetRange(evt);
1637        if (offsetRange != null) {
1638            offsetRebuild(offsetRange[0], offsetRange[1]);
1639        } else {
1640            forwardUpdate(null, evt, a, f);
1641        }
1642    }
1643    
1644    /**
1645     * Get the offset area in which the views should be rebuilt
1646     * in reaction to insert update in the underlying document.
1647     *
1648     * @param evt document event for the document modification.
1649     * @return two-item integer array containing starting and ending offset
1650     * of the area to be rebuilt or <code>null</code> in case
1651     * no views should be rebuilt.
1652     */

1653    protected int[] getInsertUpdateRebuildOffsetRange(DocumentEvent JavaDoc evt) {
1654        DocumentEvent.ElementChange JavaDoc lineChange = evt.getChange(evt.getDocument().getDefaultRootElement());
1655        if (lineChange == null) {
1656            return null;
1657        }
1658
1659        int startOffset = evt.getOffset();
1660        int endOffset = startOffset + evt.getLength();
1661        int[] offsetRange = new int[] {startOffset, endOffset};
1662        Element JavaDoc[] addedLines = lineChange.getChildrenAdded();
1663        ElementUtilities.updateOffsetRange(addedLines, offsetRange);
1664        Element JavaDoc[] removedLines = lineChange.getChildrenRemoved();
1665        ElementUtilities.updateOffsetRange(removedLines, offsetRange);
1666        return offsetRange;
1667    }
1668    
1669    public void removeUpdate(DocumentEvent JavaDoc evt, Shape JavaDoc a, ViewFactory JavaDoc f) {
1670        // #38993 - until parent is set - do not do anything
1671
if (children == null && getParent() == null) {
1672            return;
1673        }
1674
1675        if (useCustomReloadChildren()) {
1676            customRemoveUpdate(evt, a, f);
1677        } else {
1678            super.removeUpdate(evt, a, f); // default element-based update
1679
}
1680    }
1681
1682    protected void customRemoveUpdate(DocumentEvent JavaDoc evt, Shape JavaDoc a, ViewFactory JavaDoc f) {
1683        int[] offsetRange = getRemoveUpdateRebuildOffsetRange(evt);
1684        if (offsetRange != null) {
1685            offsetRebuild(offsetRange[0], offsetRange[1]);
1686        } else {
1687            forwardUpdate(null, evt, a, f);
1688        }
1689    }
1690    
1691    /**
1692     * Get the offset area in which the views should be rebuilt
1693     * in reaction to insert update in the underlying document.
1694     *
1695     * @param evt document event for the document modification.
1696     * @return two-item integer array containing starting and ending offset
1697     * of the area to be rebuilt or <code>null</code> in case
1698     * no views should be rebuilt.
1699     */

1700    protected int[] getRemoveUpdateRebuildOffsetRange(DocumentEvent JavaDoc evt) {
1701        DocumentEvent.ElementChange JavaDoc lineChange = evt.getChange(evt.getDocument().getDefaultRootElement());
1702        if (lineChange == null) {
1703            return null;
1704        }
1705
1706        int startOffset = evt.getOffset();
1707        int endOffset = startOffset;
1708        int[] offsetRange = new int[] {startOffset, endOffset};
1709        Element JavaDoc[] addedLines = lineChange.getChildrenAdded();
1710        ElementUtilities.updateOffsetRange(addedLines, offsetRange);
1711        Element JavaDoc[] removedLines = lineChange.getChildrenRemoved();
1712        ElementUtilities.updateOffsetRange(removedLines, offsetRange);
1713        return offsetRange;
1714    }
1715    
1716    public void changedUpdate(DocumentEvent JavaDoc e, Shape JavaDoc a, ViewFactory JavaDoc f) {
1717        // #38993 - until parent is set - do not do anything
1718
if (children == null && getParent() == null) {
1719            return;
1720        }
1721        
1722        super.changedUpdate(e, a, f);
1723    }
1724    
1725    /**
1726     * Load the children in the selected range of offsets.
1727     * <br>
1728     * Some implementations may reload all the present children if necessary.
1729     *
1730     * @param index index at which the views should be added/replaced.
1731     * @param removeLength number of removed children views. It is useful
1732     * when rebuilding children for a portion of the view.
1733     * @param startOffset starting offset of the loading. It can be -1
1734     * to indicate the loading from <code>View.getStartOffset()</code>.
1735     * @param endOffset ending offset of the loading. It can be -1
1736     * to indicate the loading till <code>View.getEndOffset()</code>.
1737     */

1738    protected void reloadChildren(int index, int removeLength, int startOffset, int endOffset) {
1739        if (useCustomReloadChildren()) {
1740            if (startOffset == -1) {
1741                startOffset = getStartOffset();
1742            }
1743            if (endOffset == -1) {
1744                endOffset = getEndOffset();
1745            }
1746
1747            customReloadChildren(index, removeLength, startOffset, endOffset);
1748
1749        } else { // element load of children
1750
Element JavaDoc elem = getElement();
1751            int startIndex;
1752            if (startOffset == -1) {
1753                startIndex = 0;
1754            } else {
1755                if (index == 0) {
1756                    if (startOffset != getStartOffset()) {
1757                        throw new IllegalArgumentException JavaDoc("Invalid startOffset=" + startOffset); // NOI18N
1758
}
1759                } else {
1760                    if (startOffset != getView(index - 1).getEndOffset()) {
1761                        throw new IllegalArgumentException JavaDoc("Invalid startOffset=" + startOffset); // NOI18N
1762
}
1763                }
1764                startIndex = index;
1765            }
1766
1767            int endIndex = (endOffset == -1)
1768                ? elem.getElementCount()
1769                : elem.getElementIndex(endOffset - 1) + 1;
1770
1771// TODO uncomment assert (startIndex == index);
1772

1773            elementReloadChildren(index, removeLength, endIndex - startIndex);
1774        }
1775    }
1776
1777    /**
1778     * Loads child views by tracking child elements of the element
1779     * this view was created for.
1780     * @param index index at which the views should be added/replaced.
1781     * @param removeLength number of removed children views. It is useful
1782     * when rebuilding children for a portion of the view.
1783     * @param elementIndex index of the first child element for which
1784     * the view should be created
1785     * @param elementCount number of elements for which the views should be created.
1786     */

1787    protected void elementReloadChildren(int index, int removeLength,
1788    int elementCount) {
1789
1790        Element JavaDoc e = getElement();
1791        View JavaDoc[] added = null;
1792
1793        ViewFactory JavaDoc f = getViewFactory();
1794        // Null view factory can mean that one of the grand parents is already disconnected
1795
// from the view hierarchy. No added children for null factory.
1796

1797        if (f != null) {
1798            added = new View JavaDoc[elementCount];
1799            for (int i = 0; i < elementCount; i++) {
1800                added[i] = f.create(e.getElement(index + i));
1801            }
1802
1803        }
1804
1805        replace(index, removeLength, added);
1806    }
1807    
1808    /**
1809     * Loads child views in a custom way.
1810     *
1811     * @param index index at which the views should be added/replaced.
1812     * @param removeLength number of removed children views. It is useful
1813     * when rebuilding children for a portion of the view.
1814     * @param startOffset starting offset from which the loading starts.
1815     * @param endOffset ending offset where the loading ends.
1816     */

1817    protected void customReloadChildren(int index, int removeLength,
1818    int startOffset, int endOffset) {
1819
1820        View JavaDoc[] added = null;
1821        ViewFactory JavaDoc f = getViewFactory();
1822        // Null view factory can mean that one of the grand parents is already disconnected
1823
// from the view hierarchy. No added children for null factory.
1824

1825        if (f != null) {
1826            Element JavaDoc elem = getElement();
1827
1828            int elementCount = elem.getElementCount();
1829            int elementIndex = (elem != null) ? elem.getElementIndex(startOffset) : -1;
1830            if (elementIndex >= elementCount) {
1831                return; // Create no after last element
1832
}
1833            List JavaDoc childViews = new ArrayList JavaDoc();
1834            int viewCount = getViewCount();
1835
1836            while (startOffset < endOffset) {
1837                // Create custom child
1838
View JavaDoc childView = createCustomView(f, startOffset, endOffset, elementIndex);
1839                if (childView == null) {
1840                    throw new IllegalStateException JavaDoc("No view created for area (" // NOI18N
1841
+ startOffset + ", " + endOffset + ")"); // NOI18N
1842
}
1843
1844                // Assuming childView.getStartOffset() is at startOffset
1845
childViews.add(childView);
1846
1847                // Update elementIndex
1848
int childViewEndOffset = childView.getEndOffset();
1849                while (childViewEndOffset > endOffset) {
1850/* throw new IllegalStateException(
1851                        "childViewEndOffset=" + childViewEndOffset // NOI18N
1852                        + " > endOffset=" + endOffset // NOI18N
1853                    );
1854 */

1855                    /* The created child view interferes with a view
1856                     * that is still present and which is not planned
1857                     * to be removed.
1858                     * This can happen e.g. when a fold hierarchy change
1859                     * (caused by a document change) is fired
1860                     * prior to the document change gets fired
1861                     * to the view hierarchy.
1862                     * The fix for that situation is to continue to remove
1863                     * the present views until the end of the created view will match
1864                     * a beginning of a present view.
1865                     */

1866                    if (index + removeLength >= viewCount) {
1867                        // Should not happen but can't remove past the last view
1868
break;
1869                    }
1870                    endOffset = getView(index + removeLength).getEndOffset();
1871                    removeLength++;
1872                    if (debugRebuild) {
1873                        /*DEBUG*/System.err.println(
1874                            "GapBoxView.customReloadChildren(): Increased removeLength to " // NOI18N
1875
+ removeLength + ", eo=" + endOffset // NOI18N
1876
);
1877                    }
1878                }
1879
1880                Element JavaDoc childElem = elem.getElement(elementIndex);
1881                while (childElem.getEndOffset() <= childViewEndOffset) {
1882                    elementIndex++;
1883                    if (elementIndex == elementCount) {
1884                        break;
1885                    }
1886                    childElem = elem.getElement(elementIndex);
1887                }
1888
1889                startOffset = childViewEndOffset;
1890            }
1891
1892            added = new View JavaDoc[childViews.size()];
1893            childViews.toArray(added);
1894        }
1895
1896        replace(index, removeLength, added);
1897    }
1898    
1899    /**
1900     * Create custom child view starting at <code>startOffset</code>.
1901     *
1902     * @param f view factory to be used.
1903     * @param startOffset offset at which the created view must start.
1904     * @param maxEndOffset maximum ending offset to which the created view
1905     * may span.
1906     * @param elementIndex index of the child element that best represents
1907     * the startOffset. The element is child of the element that this view
1908     * is responsible for. If this view is not based by element then this
1909     * parameter will be -1.
1910     */

1911    protected View JavaDoc createCustomView(ViewFactory JavaDoc f,
1912    int startOffset, int maxEndOffset, int elementIndex) {
1913
1914
1915/*
1916        // Default implementation delegating to view factory
1917        // is here just to show the possible functionality
1918        // and clarify the variables
1919
1920        View v;
1921        if (parentElement != null) {
1922            Element elem = parentElement.getElement(elementIndex);
1923            if (elem.getStartOffset() != startOffset) {
1924                throw new IllegalStateException("Not element boundary");
1925            }
1926
1927            if (elem.getEndOffset() > maxEndOffset) {
1928                throw new IllegalStateException("Beyond maximum ending offset");
1929            }
1930
1931            v = f.create(elem);
1932
1933        } else { // no element - need more information
1934            return null;
1935        }
1936 */

1937            
1938        return null;
1939    }
1940
1941    /**
1942     * Subclasses may override this method and deallocate resources
1943     * bound to presence of children.
1944     * <br>
1945     * It's called by {@link #releaseChildren()} to unallocate
1946     * the resources for children.
1947     *
1948     * <p>
1949     * Once this method finishes all the children will
1950     * be set null as a parent and the reference
1951     * to children will be cleared.
1952     */

1953    protected void unloadChildren() {
1954    }
1955    
1956    /**
1957     * New ViewLayoutState records are created through
1958     * this method to allow subclasses the extend
1959     * the ViewLayoutState records to do/hold more
1960     */

1961    protected ViewLayoutState createChild(View JavaDoc v) {
1962        ViewLayoutState child;
1963        if (v instanceof ViewLayoutState) {
1964            child = (ViewLayoutState)v;
1965        } else { // view does not implement ViewLayoutState
1966
child = createDefaultChild(v);
1967        }
1968        return child;
1969    }
1970
1971    /**
1972     * Return default implementation of the view layout state wrapper.
1973     */

1974    protected ViewLayoutState createDefaultChild(View JavaDoc v) {
1975        return new SimpleViewLayoutState(v); // only handle preferred spans
1976
}
1977    
1978    protected final boolean isMajorAxisPreferenceChanged() {
1979        return (isStatusBitsNonZero(MAJOR_AXIS_PREFERENCE_CHANGED_BIT));
1980    }
1981
1982    protected void markMajorAxisPreferenceChanged() {
1983        setStatusBits(MAJOR_AXIS_PREFERENCE_CHANGED_BIT);
1984    }
1985    
1986    protected final boolean isMinorAxisPreferenceChanged() {
1987        return (isStatusBitsNonZero(MINOR_AXIS_PREFERENCE_CHANGED_BIT));
1988    }
1989
1990    protected void markMinorAxisPreferenceChanged() {
1991        setStatusBits(MINOR_AXIS_PREFERENCE_CHANGED_BIT);
1992    }
1993    
1994    protected final void resetAxesPreferenceChanged() {
1995        clearStatusBits(MAJOR_AXIS_PREFERENCE_CHANGED_BIT | MINOR_AXIS_PREFERENCE_CHANGED_BIT);
1996    }
1997    
1998    /**
1999     * Get the span along an axis that is taken up by the view insets.
2000     *
2001     * @param axis the axis to determine the total insets along,
2002     * either X_AXIS or Y_AXIS.
2003     * @return span along the given axis taken up by view insets.
2004     */

2005    protected final float getInsetSpan(int axis) {
2006// assert ViewUtilities.isAxisValid(axis);
2007

2008        ViewInsets insets = getInsets();
2009        return (insets != null)
2010            ? ((axis == X_AXIS) ? insets.getLeftRight() : insets.getTopBottom())
2011            : 0;
2012    }
2013
2014    /**
2015     * Get the span along major axis that is taken up by the view insets.
2016     *
2017     * @return span along major axis taken up by view insets.
2018     */

2019    protected final float getMajorAxisInsetSpan() {
2020        ViewInsets insets = getInsets();
2021        return (insets != null)
2022            ? (isXMajorAxis() ? insets.getLeftRight() : insets.getTopBottom())
2023            : 0;
2024    }
2025
2026    /**
2027     * Get the span along minor axis that is taken up by the view insets.
2028     *
2029     * @return span along minor axis taken up by view insets.
2030     */

2031    protected final float getMinorAxisInsetSpan() {
2032        ViewInsets insets = getInsets();
2033        return (insets != null)
2034            ? (isXMajorAxis() ? insets.getTopBottom() : insets.getLeftRight())
2035            : 0;
2036    }
2037
2038    protected final int getStatusBits(int bits) {
2039        return (statusBits & bits);
2040    }
2041    
2042    protected final boolean isStatusBitsNonZero(int bits) {
2043        return (getStatusBits(bits) != 0);
2044    }
2045    
2046    protected final void setStatusBits(int bits) {
2047        statusBits |= bits;
2048    }
2049    
2050    protected final void clearStatusBits(int bits) {
2051        statusBits &= ~bits;
2052    }
2053
2054    /**
2055     * Reallocate the view to the new size given by the passed shape.
2056     *
2057     * @param a shape to which to reallocate the view.
2058     * @return rectangle bounding the shape. The returned rectangle
2059     * can be mutated.
2060     */

2061    protected Rectangle JavaDoc reallocate(Shape JavaDoc a) {
2062        Rectangle JavaDoc alloc = a.getBounds(); // makes a fresh rectangle instance
2063

2064        setSize(alloc.width, alloc.height); // set new size
2065

2066        return alloc;
2067    }
2068
2069    // Implements FlyView.Parent
2070
public int getStartOffset(int childViewIndex) {
2071        return getChildren().getChildStartOffset(childViewIndex);
2072    }
2073    
2074    // Implements FlyView.Parent
2075
public int getEndOffset(int childViewIndex) {
2076        return getChildren().getChildEndOffset(childViewIndex);
2077    }
2078    
2079    public String JavaDoc childToString(int childIndex) {
2080        StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
2081        appendChildToStringBuffer(sb, childIndex, 0);
2082        return sb.toString();
2083    }
2084
2085    public void appendChildToStringBuffer(StringBuffer JavaDoc sb, int childIndex, int indent) {
2086        ViewLayoutState child = getChild(childIndex);
2087        View JavaDoc childView = child.getView();
2088        Document JavaDoc doc = getDocument();
2089        boolean isFly = child.isFlyweight();
2090        boolean isEstimated = (childView instanceof EstimatedSpanView)
2091            && ((EstimatedSpanView)childView).isEstimatedSpan();
2092        boolean layoutValid = child.isLayoutValid();
2093        double offset = children.getMajorAxisOffset(childIndex);
2094        boolean indexesDiffer = !isFly && (getChildIndexNoCheck(child) != childIndex);
2095        boolean showRaw = false; // change for debugging purposes
2096

2097        sb.append((isFly ? 'F' : 'R')); // flyweight / regular NOI18N
2098
sb.append(':');
2099        if (indexesDiffer) {
2100            sb.append(" WRONG-INDEX=" + getChildIndexNoCheck(child)); // NOI18N
2101
}
2102        if (showRaw) {
2103            sb.append("rI=" + child.getViewRawIndex()); // NOI18N
2104
}
2105        sb.append('<');
2106        appendOffsetInfo(sb, doc, childView.getStartOffset());
2107        sb.append(',');
2108        appendOffsetInfo(sb, doc, childView.getEndOffset());
2109        sb.append('>');
2110            
2111        sb.append(", major=").append(child.getLayoutMajorAxisPreferredSpan()); // NOI18N
2112
sb.append("(off=").append(offset); // NOI18N
2113

2114        if (showRaw) {
2115            sb.append('(').append(child.getLayoutMajorAxisRawOffset()).append(')'); // NOI18N
2116
}
2117        
2118        sb.append("), minor[pref=").append(child.getLayoutMinorAxisPreferredSpan()); // NOI18N
2119
sb.append(", min=").append(child.getLayoutMinorAxisMinimumSpan()); // NOI18N
2120
sb.append(", max=").append(child.getLayoutMinorAxisMaximumSpan()); // NOI18N
2121
sb.append("] "); // NOI18N
2122
sb.append(isEstimated ? "E" : ""); // NOI18N
2123
sb.append(layoutValid ? "" : "I"); // NOI18N
2124

2125        // Possibly add view description if GapBoxView
2126
if (childView instanceof GapBoxView) {
2127            sb.append("\n"); // NOI18N
2128
appendSpaces(sb, indent + 4);
2129            sb.append("VIEW: "); // NOI18N
2130
sb.append(childView.toString());
2131            sb.append(((GapBoxView)childView).childrenToString(indent + 4));
2132        }
2133    }
2134    
2135    private static void appendOffsetInfo(StringBuffer JavaDoc sb, Document JavaDoc doc, int offset) {
2136        sb.append(offset);
2137        sb.append('[');
2138        // TODO - removed dependency on o.n.e.Utilities
2139
sb.append(org.netbeans.editor.Utilities.debugPosition(
2140            (org.netbeans.editor.BaseDocument)doc, offset));
2141        sb.append(']');
2142    }
2143    
2144    private static void appendSpaces(StringBuffer JavaDoc sb, int spaceCount) {
2145        while (--spaceCount >= 0) {
2146            sb.append(' ');
2147        }
2148    }
2149
2150    public String JavaDoc childrenToString() {
2151        return childrenToString(0);
2152    }
2153
2154    public String JavaDoc childrenToString(int indent) {
2155        StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
2156
2157        int viewCount = getViewCount();
2158        int totalDigitCount = Integer.toString(viewCount).length();
2159        for (int i = 0; i < viewCount; i++) {
2160            sb.append('\n');
2161            String JavaDoc iToString = Integer.toString(i);
2162            appendSpaces(sb, indent + (totalDigitCount - iToString.length()));
2163
2164            sb.append('[');
2165            sb.append(iToString);
2166            sb.append("]: "); // NOI18N
2167
appendChildToStringBuffer(sb, i, indent);
2168        }
2169
2170        return sb.toString();
2171    }
2172
2173    public String JavaDoc toString() {
2174        // Must not return anything about children because
2175
// that could cause them to be initialized (e.g. by getViewCount())
2176
return "lastMajorAxisPreferredSpan=" + lastMajorAxisPreferredSpan // NOI18N
2177
+ ", lastMinorAxisPreferredSpan=" + lastMinorAxisPreferredSpan // NOI18N
2178
+ ", minorAxisAssignedSpan=" + getMinorAxisAssignedSpan(); // NOI18N
2179
}
2180
2181}
2182
Popular Tags