KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > text > View


1 /*
2  * @(#)View.java 1.70 04/05/18
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package javax.swing.text;
8
9 import java.awt.*;
10 import javax.swing.SwingConstants JavaDoc;
11 import javax.swing.event.*;
12
13 /**
14  * <p>
15  * A very important part of the text package is the <code>View</code> class.
16  * As the name suggests it represents a view of the text model,
17  * or a piece of the text model.
18  * It is this class that is responsible for the look of the text component.
19  * The view is not intended to be some completely new thing that one must
20  * learn, but rather is much like a lightweight component.
21  * In fact, the original <code>View</code> implementation was a
22  * lightweight component. There were several reasons why
23  * the <code>Component</code> implementation was abandoned in favor of
24  * an alternative.
25  * <ol>
26  * <li>
27  * <p>
28  * There was barely time to get the lightweight component support in the
29  * 1.1 version of the JDK. There simply wasn't time to lighten up the
30  * component further to where it would need to be to be used for text purposes.
31  * The additions made to <code>JComponent</code> increased the memory
32  * consumption, and as it currently stands its much too heavy for
33  * representing text.
34  * </p>
35  * <li>
36  * <p>
37  * The layout semantics aren't quite right for text,
38  * and changing the current layout
39  * semantics of component might break existing applications.
40  * </p>
41  * <li>
42  * <p>
43  * The component api uses integers, but in 1.2 one can use floating point
44  * device independent coordinates. An api that works in both 1.1 and 1.2
45  * would be convenient for minimizing transition difficulties. The
46  * <code>View</code> class uses the <code>Shape</code> interface and
47  * float arguments to enable View implementations for the Java 2 platform
48  * v1.2 and later while still functioning in the older 1.1 JDK.
49  * </p>
50  * </ol>
51  * <p>
52 By default, a view is very light. It contains a reference to the parent
53 view from which it can fetch many things without holding state, and it
54 contains a reference to a portion of the model (</code>Element</code>).
55 A view does not
56 have to exactly represent an element in the model, that is simply a typical
57 and therefore convenient mapping. A view can alternatively maintain a couple
58 of Position objects to maintain its location in the model (i.e. represent
59 a fragment of an element). This is typically the result of formatting where
60 views have been broken down into pieces. The convenience of a substantial
61 relationship to the element makes it easier to build factories to produce the
62 views, and makes it easier to keep track of the view pieces as the model is
63 changed and the view must be changed to reflect the model. Simple views
64 therefore represent an Element directly and complex views do not.
65 <p>
66 A view has the following responsibilities:
67   <dl>
68
69     <dt><b>Participate in layout.</b>
70     <dd>
71     <p>The view has a <code>setSize</code> method which is like
72     <code>doLayout</code> and <code>setSize</code> in <code>Component</code> combined.
73     The view has a <code>preferenceChanged</code> method which is
74     like <code>invalidate</code> in <code>Component</code> except that one can
75     invalidate just one axis
76     and the child requesting the change is identified.
77     <p>A View expresses the size that it would like to be in terms of three
78     values, a minimum, a preferred, and a maximum span. Layout in a view is
79     can be done independently upon each axis. For a properly functioning View
80     implementation, the minimum span will be &lt;= the preferred span which in turn
81     will be &lt;= the maximum span.
82     </p>
83     <p align=center><img SRC="doc-files/View-flexibility.jpg"
84                      alt="The above text describes this graphic.">
85     <p>The minimum set of methods for layout are:
86     <ul>
87     <li><a HREF="#getMinimumSpan(int)">getMinimumSpan</a>
88     <li><a HREF="#getPreferredSpan(int)">getPreferredSpan</a>
89     <li><a HREF="#getMaximumSpan(int)">getMaximumSpan</a>
90     <li><a HREF="#getAlignment(int)">getAlignment</a>
91     <li><a HREF="#preferenceChanged(javax.swing.text.View, boolean, boolean)">preferenceChanged</a>
92     <li><a HREF="#setSize(float, float)">setSize</a>
93     </ul>
94   
95   <p>The <code>setSize</code> method should be prepared to be called a number of times
96     (i.e. It may be called even if the size didn't change).
97     The <code>setSize</code> method
98     is generally called to make sure the View layout is complete prior to trying
99     to perform an operation on it that requires an up-to-date layout. A view's
100     size should <em>always</em> be set to a value within the minimum and maximum
101     span specified by that view. Additionally, the view must always call the
102     <code>preferenceChanged</code> method on the parent if it has changed the
103     values for the
104     layout it would like, and expects the parent to honor. The parent View is
105     not required to recognize a change until the <code>preferenceChanged</code>
106     has been sent.
107     This allows parent View implementations to cache the child requirements if
108     desired. The calling sequence looks something like the following:
109     </p>
110     <p align=center>
111       <img SRC="doc-files/View-layout.jpg"
112        alt="Sample calling sequence between parent view and child view:
113        setSize, getMinimum, getPreferred, getMaximum, getAlignment, setSize">
114     <p>The exact calling sequence is up to the layout functionality of
115     the parent view (if the view has any children). The view may collect
116     the preferences of the children prior to determining what it will give
117     each child, or it might iteratively update the children one at a time.
118     </p>
119
120     <dt><b>Render a portion of the model.</b>
121     <dd>
122     <p>This is done in the paint method, which is pretty much like a component
123     paint method. Views are expected to potentially populate a fairly large
124     tree. A <code>View</code> has the following semantics for rendering:
125     </p>
126     <ul>
127     <li>The view gets its allocation from the parent at paint time, so it
128     must be prepared to redo layout if the allocated area is different from
129     what it is prepared to deal with.
130     <li>The coordinate system is the same as the hosting <code>Component</code>
131     (i.e. the <code>Component</code> returned by the
132     <a HREF="#getContainer">getContainer</a> method).
133     This means a child view lives in the same coordinate system as the parent
134     view unless the parent has explicitly changed the coordinate system.
135     To schedule itself to be repainted a view can call repaint on the hosting
136     <code>Component</code>.
137     <li>The default is to <em>not clip</em> the children. It is more efficient
138     to allow a view to clip only if it really feels it needs clipping.
139     <li>The <code>Graphics</code> object given is not initialized in any way.
140     A view should set any settings needed.
141     <li>A <code>View</code> is inherently transparent. While a view may render into its
142     entire allocation, typically a view does not. Rendering is performed by
143     tranversing down the tree of <code>View</code> implementations.
144     Each <code>View</code> is responsible
145     for rendering its children. This behavior is depended upon for thread
146     safety. While view implementations do not necessarily have to be implemented
147     with thread safety in mind, other view implementations that do make use of
148     concurrency can depend upon a tree traversal to guarantee thread safety.
149     <li>The order of views relative to the model is up to the implementation.
150     Although child views will typically be arranged in the same order that they
151     occur in the model, they may be visually arranged in an entirely different
152     order. View implementations may have Z-Order associated with them if the
153     children are overlapping.
154     </ul>
155     <p>The methods for rendering are:
156     <ul>
157     <li><a HREF="#paint(java.awt.Graphics, java.awt.Shape)">paint</a>
158     </ul>
159     <p>
160
161     <dt><b>Translate between the model and view coordinate systems.</b>
162     <dd>
163     <p>Because the view objects are produced from a factory and therefore cannot
164     necessarily be counted upon to be in a particular pattern, one must be able
165     to perform translation to properly locate spatial representation of the model.
166     The methods for doing this are:
167     <ul>
168     <li><a HREF="#modelToView(int, javax.swing.text.Position.Bias, int, javax.swing.text.Position.Bias, java.awt.Shape)">modelToView</a>
169     <li><a HREF="#viewToModel(float, float, java.awt.Shape, javax.swing.text.Position.Bias[])">viewToModel</a>
170     <li><a HREF="#getDocument()">getDocument</a>
171     <li><a HREF="#getElement()">getElement</a>
172     <li><a HREF="#getStartOffset()">getStartOffset</a>
173     <li><a HREF="#getEndOffset()">getEndOffset</a>
174     </ul>
175     <p>The layout must be valid prior to attempting to make the translation.
176     The translation is not valid, and must not be attempted while changes
177     are being broadcasted from the model via a <code>DocumentEvent</code>.
178     </p>
179
180     <dt><b>Respond to changes from the model.</b>
181     <dd>
182     <p>If the overall view is represented by many pieces (which is the best situation
183     if one want to be able to change the view and write the least amount of new code),
184     it would be impractical to have a huge number of <code>DocumentListener</code>s.
185     If each
186     view listened to the model, only a few would actually be interested in the
187     changes broadcasted at any given time. Since the model has no knowledge of
188     views, it has no way to filter the broadcast of change information. The view
189     hierarchy itself is instead responsible for propagating the change information.
190     At any level in the view hierarchy, that view knows enough about its children to
191     best distribute the change information further. Changes are therefore broadcasted
192     starting from the root of the view hierarchy.
193     The methods for doing this are:
194     <ul>
195     <li><a HREF="#insertUpdate">insertUpdate</a>
196     <li><a HREF="#removeUpdate">removeUpdate</a>
197     <li><a HREF="#changedUpdate">changedUpdate</a>
198     </ul>
199     <p>
200 </dl>
201  *
202  * @author Timothy Prinzing
203  * @version 1.70 05/18/04
204  */

205 public abstract class View implements SwingConstants JavaDoc {
206
207     /**
208      * Creates a new <code>View</code> object.
209      *
210      * @param elem the <code>Element</code> to represent
211      */

212     public View(Element JavaDoc elem) {
213     this.elem = elem;
214     }
215
216     /**
217      * Returns the parent of the view.
218      *
219      * @return the parent, or <code>null</code> if none exists
220      */

221     public View JavaDoc getParent() {
222     return parent;
223     }
224
225     /**
226      * Returns a boolean that indicates whether
227      * the view is visible or not. By default
228      * all views are visible.
229      *
230      * @return always returns true
231      */

232     public boolean isVisible() {
233     return true;
234     }
235
236     
237     /**
238      * Determines the preferred span for this view along an
239      * axis.
240      *
241      * @param axis may be either <code>View.X_AXIS</code> or
242      * <code>View.Y_AXIS</code>
243      * @return the span the view would like to be rendered into.
244      * Typically the view is told to render into the span
245      * that is returned, although there is no guarantee.
246      * The parent may choose to resize or break the view
247      * @see View#getPreferredSpan
248      */

249     public abstract float getPreferredSpan(int axis);
250
251     /**
252      * Determines the minimum span for this view along an
253      * axis.
254      *
255      * @param axis may be either <code>View.X_AXIS</code> or
256      * <code>View.Y_AXIS</code>
257      * @return the minimum span the view can be rendered into
258      * @see View#getPreferredSpan
259      */

260     public float getMinimumSpan(int axis) {
261     int w = getResizeWeight(axis);
262     if (w == 0) {
263         // can't resize
264
return getPreferredSpan(axis);
265     }
266     return 0;
267     }
268
269     /**
270      * Determines the maximum span for this view along an
271      * axis.
272      *
273      * @param axis may be either <code>View.X_AXIS</code> or
274      * <code>View.Y_AXIS</code>
275      * @return the maximum span the view can be rendered into
276      * @see View#getPreferredSpan
277      */

278     public float getMaximumSpan(int axis) {
279     int w = getResizeWeight(axis);
280     if (w == 0) {
281         // can't resize
282
return getPreferredSpan(axis);
283     }
284     return Integer.MAX_VALUE;
285     }
286     
287     /**
288      * Child views can call this on the parent to indicate that
289      * the preference has changed and should be reconsidered
290      * for layout. By default this just propagates upward to
291      * the next parent. The root view will call
292      * <code>revalidate</code> on the associated text component.
293      *
294      * @param child the child view
295      * @param width true if the width preference has changed
296      * @param height true if the height preference has changed
297      * @see javax.swing.JComponent#revalidate
298      */

299     public void preferenceChanged(View JavaDoc child, boolean width, boolean height) {
300     View JavaDoc parent = getParent();
301     if (parent != null) {
302         parent.preferenceChanged(this, width, height);
303     }
304     }
305
306     /**
307      * Determines the desired alignment for this view along an
308      * axis. The desired alignment is returned. This should be
309      * a value >= 0.0 and <= 1.0, where 0 indicates alignment at
310      * the origin and 1.0 indicates alignment to the full span
311      * away from the origin. An alignment of 0.5 would be the
312      * center of the view.
313      *
314      * @param axis may be either <code>View.X_AXIS</code> or
315      * <code>View.Y_AXIS</code>
316      * @return the value 0.5
317      */

318     public float getAlignment(int axis) {
319     return 0.5f;
320     }
321
322     /**
323      * Renders using the given rendering surface and area on that
324      * surface. The view may need to do layout and create child
325      * views to enable itself to render into the given allocation.
326      *
327      * @param g the rendering surface to use
328      * @param allocation the allocated region to render into
329      * @see View#paint
330      */

331     public abstract void paint(Graphics g, Shape allocation);
332
333     /**
334      * Establishes the parent view for this view. This is
335      * guaranteed to be called before any other methods if the
336      * parent view is functioning properly. This is also
337      * the last method called, since it is called to indicate
338      * the view has been removed from the hierarchy as
339      * well. When this method is called to set the parent to
340      * null, this method does the same for each of its children,
341      * propogating the notification that they have been
342      * disconnected from the view tree. If this is
343      * reimplemented, <code>super.setParent()</code> should
344      * be called.
345      *
346      * @param parent the new parent, or <code>null</code> if the view is
347      * being removed from a parent
348      */

349     public void setParent(View JavaDoc parent) {
350         // if the parent is null then propogate down the view tree
351
if (parent == null) {
352             for (int i = 0; i < getViewCount(); i++) {
353         if (getView(i).getParent() == this) {
354             // in FlowView.java view might be referenced
355
// from two super-views as a child. see logicalView
356
getView(i).setParent(null);
357         }
358             }
359         }
360         this.parent = parent;
361     }
362
363     /**
364      * Returns the number of views in this view. Since
365      * the default is to not be a composite view this
366      * returns 0.
367      *
368      * @return the number of views >= 0
369      * @see View#getViewCount
370      */

371     public int getViewCount() {
372     return 0;
373     }
374
375     /**
376      * Gets the <i>n</i>th child view. Since there are no
377      * children by default, this returns <code>null</code>.
378      *
379      * @param n the number of the view to get, >= 0 && < getViewCount()
380      * @return the view
381      */

382     public View JavaDoc getView(int n) {
383     return null;
384     }
385
386
387     /**
388      * Removes all of the children. This is a convenience
389      * call to <code>replace</code>.
390      *
391      * @since 1.3
392      */

393     public void removeAll() {
394     replace(0, getViewCount(), null);
395     }
396
397     /**
398      * Removes one of the children at the given position.
399      * This is a convenience call to <code>replace</code>.
400      * @since 1.3
401      */

402     public void remove(int i) {
403     replace(i, 1, null);
404     }
405
406     /**
407      * Inserts a single child view. This is a convenience
408      * call to <code>replace</code>.
409      *
410      * @param offs the offset of the view to insert before >= 0
411      * @param v the view
412      * @see #replace
413      * @since 1.3
414      */

415     public void insert(int offs, View JavaDoc v) {
416     View JavaDoc[] one = new View JavaDoc[1];
417     one[0] = v;
418     replace(offs, 0, one);
419     }
420
421     /**
422      * Appends a single child view. This is a convenience
423      * call to <code>replace</code>.
424      *
425      * @param v the view
426      * @see #replace
427      * @since 1.3
428      */

429     public void append(View JavaDoc v) {
430     View JavaDoc[] one = new View JavaDoc[1];
431     one[0] = v;
432     replace(getViewCount(), 0, one);
433     }
434
435     /**
436      * Replaces child views. If there are no views to remove
437      * this acts as an insert. If there are no views to
438      * add this acts as a remove. Views being removed will
439      * have the parent set to <code>null</code>, and the internal reference
440      * to them removed so that they can be garbage collected.
441      * This is implemented to do nothing, because by default
442      * a view has no children.
443      *
444      * @param offset the starting index into the child views to insert
445      * the new views. This should be a value >= 0 and <= getViewCount
446      * @param length the number of existing child views to remove
447      * This should be a value >= 0 and <= (getViewCount() - offset).
448      * @param views the child views to add. This value can be
449      * <code>null</code> to indicate no children are being added
450      * (useful to remove).
451      * @since 1.3
452      */

453     public void replace(int offset, int length, View JavaDoc[] views) {
454     }
455
456     /**
457      * Returns the child view index representing the given position in
458      * the model. By default a view has no children so this is implemented
459      * to return -1 to indicate there is no valid child index for any
460      * position.
461      *
462      * @param pos the position >= 0
463      * @return index of the view representing the given position, or
464      * -1 if no view represents that position
465      * @since 1.3
466      */

467     public int getViewIndex(int pos, Position.Bias JavaDoc b) {
468     return -1;
469     }
470     
471     /**
472      * Fetches the allocation for the given child view.
473      * This enables finding out where various views
474      * are located, without assuming how the views store
475      * their location. This returns <code>null</code> since the
476      * default is to not have any child views.
477      *
478      * @param index the index of the child, >= 0 && <
479      * <code>getViewCount()</code>
480      * @param a the allocation to this view
481      * @return the allocation to the child
482      */

483     public Shape getChildAllocation(int index, Shape a) {
484     return null;
485     }
486
487     /**
488      * Provides a way to determine the next visually represented model
489      * location at which one might place a caret.
490      * Some views may not be visible,
491      * they might not be in the same order found in the model, or they just
492      * might not allow access to some of the locations in the model.
493      *
494      * @param pos the position to convert >= 0
495      * @param a the allocated region in which to render
496      * @param direction the direction from the current position that can
497      * be thought of as the arrow keys typically found on a keyboard.
498      * This will be one of the following values:
499      * <ul>
500      * <li>SwingConstants.WEST
501      * <li>SwingConstants.EAST
502      * <li>SwingConstants.NORTH
503      * <li>SwingConstants.SOUTH
504      * </ul>
505      * @return the location within the model that best represents the next
506      * location visual position
507      * @exception BadLocationException
508      * @exception IllegalArgumentException if <code>direction</code>
509      * doesn't have one of the legal values above
510      */

511     public int getNextVisualPositionFrom(int pos, Position.Bias JavaDoc b, Shape a,
512                      int direction, Position.Bias JavaDoc[] biasRet)
513       throws BadLocationException JavaDoc {
514
515     biasRet[0] = Position.Bias.Forward;
516     switch (direction) {
517     case NORTH:
518     case SOUTH:
519     {
520         if (pos == -1) {
521         pos = (direction == NORTH) ? Math.max(0, getEndOffset() - 1) :
522             getStartOffset();
523         break;
524         }
525         JTextComponent JavaDoc target = (JTextComponent JavaDoc) getContainer();
526         Caret JavaDoc c = (target != null) ? target.getCaret() : null;
527         // YECK! Ideally, the x location from the magic caret position
528
// would be passed in.
529
Point mcp;
530         if (c != null) {
531         mcp = c.getMagicCaretPosition();
532         }
533         else {
534         mcp = null;
535         }
536         int x;
537         if (mcp == null) {
538         Rectangle loc = target.modelToView(pos);
539         x = (loc == null) ? 0 : loc.x;
540         }
541         else {
542         x = mcp.x;
543         }
544         if (direction == NORTH) {
545         pos = Utilities.getPositionAbove(target, pos, x);
546         }
547         else {
548         pos = Utilities.getPositionBelow(target, pos, x);
549         }
550     }
551         break;
552     case WEST:
553         if(pos == -1) {
554         pos = Math.max(0, getEndOffset() - 1);
555         }
556         else {
557         pos = Math.max(0, pos - 1);
558         }
559         break;
560     case EAST:
561         if(pos == -1) {
562         pos = getStartOffset();
563         }
564         else {
565         pos = Math.min(pos + 1, getDocument().getLength());
566         }
567         break;
568     default:
569         throw new IllegalArgumentException JavaDoc("Bad direction: " + direction);
570     }
571     return pos;
572     }
573
574     /**
575      * Provides a mapping, for a given character,
576      * from the document model coordinate space
577      * to the view coordinate space.
578      *
579      * @param pos the position of the desired character (>=0)
580      * @param a the area of the view, which encompasses the requested character
581      * @param b the bias toward the previous character or the
582      * next character represented by the offset, in case the
583      * position is a boundary of two views; <code>b</code> will have one
584      * of these values:
585      * <ul>
586      * <li> <code>Position.Bias.Forward</code>
587      * <li> <code>Position.Bias.Backward</code>
588      * </ul>
589      * @return the bounding box, in view coordinate space,
590      * of the character at the specified position
591      * @exception BadLocationException if the specified position does
592      * not represent a valid location in the associated document
593      * @exception IllegalArgumentException if <code>b</code> is not one of the
594      * legal <code>Position.Bias</code> values listed above
595      * @see View#viewToModel
596      */

597     public abstract Shape modelToView(int pos, Shape a, Position.Bias JavaDoc b) throws BadLocationException JavaDoc;
598
599     /**
600      * Provides a mapping, for a given region,
601      * from the document model coordinate space
602      * to the view coordinate space. The specified region is
603      * created as a union of the first and last character positions.
604      *
605      * @param p0 the position of the first character (>=0)
606      * @param b0 the bias of the first character position,
607      * toward the previous character or the
608      * next character represented by the offset, in case the
609      * position is a boundary of two views; <code>b0</code> will have one
610      * of these values:
611      * <ul>
612      * <li> <code>Position.Bias.Forward</code>
613      * <li> <code>Position.Bias.Backward</code>
614      * </ul>
615      * @param p1 the position of the last character (>=0)
616      * @param b1 the bias for the second character position, defined
617      * one of the legal values shown above
618      * @param a the area of the view, which encompasses the requested region
619      * @return the bounding box which is a union of the region specified
620      * by the first and last character positions
621      * @exception BadLocationException if the given position does
622      * not represent a valid location in the associated document
623      * @exception IllegalArgumentException if <code>b0</code> or
624      * <code>b1</code> are not one of the
625      * legal <code>Position.Bias</code> values listed above
626      * @see View#viewToModel
627      */

628     public Shape modelToView(int p0, Position.Bias JavaDoc b0, int p1, Position.Bias JavaDoc b1, Shape a) throws BadLocationException JavaDoc {
629     Shape s0 = modelToView(p0, a, b0);
630     Shape s1;
631     if (p1 == getEndOffset()) {
632         try {
633         s1 = modelToView(p1, a, b1);
634         } catch (BadLocationException JavaDoc ble) {
635         s1 = null;
636         }
637         if (s1 == null) {
638         // Assume extends left to right.
639
Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
640                           a.getBounds();
641         s1 = new Rectangle(alloc.x + alloc.width - 1, alloc.y,
642                    1, alloc.height);
643         }
644     }
645     else {
646         s1 = modelToView(p1, a, b1);
647     }
648     Rectangle r0 = s0.getBounds();
649     Rectangle r1 = (s1 instanceof Rectangle) ? (Rectangle) s1 :
650                                                s1.getBounds();
651     if (r0.y != r1.y) {
652         // If it spans lines, force it to be the width of the view.
653
Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
654                       a.getBounds();
655         r0.x = alloc.x;
656         r0.width = alloc.width;
657     }
658     r0.add(r1);
659     return r0;
660     }
661
662     /**
663      * Provides a mapping from the view coordinate space to the logical
664      * coordinate space of the model. The <code>biasReturn</code>
665      * argument will be filled in to indicate that the point given is
666      * closer to the next character in the model or the previous
667      * character in the model.
668      *
669      * @param x the X coordinate >= 0
670      * @param y the Y coordinate >= 0
671      * @param a the allocated region in which to render
672      * @return the location within the model that best represents the
673      * given point in the view >= 0. The <code>biasReturn</code>
674      * argument will be
675      * filled in to indicate that the point given is closer to the next
676      * character in the model or the previous character in the model.
677      */

678     public abstract int viewToModel(float x, float y, Shape a, Position.Bias JavaDoc[] biasReturn);
679
680     /**
681      * Gives notification that something was inserted into
682      * the document in a location that this view is responsible for.
683      * To reduce the burden to subclasses, this functionality is
684      * spread out into the following calls that subclasses can
685      * reimplement:
686      * <ol>
687      * <li><a HREF="#updateChildren">updateChildren</a> is called
688      * if there were any changes to the element this view is
689      * responsible for. If this view has child views that are
690      * represent the child elements, then this method should do
691      * whatever is necessary to make sure the child views correctly
692      * represent the model.
693      * <li><a HREF="#forwardUpdate">forwardUpdate</a> is called
694      * to forward the DocumentEvent to the appropriate child views.
695      * <li><a HREF="#updateLayout">updateLayout</a> is called to
696      * give the view a chance to either repair its layout, to reschedule
697      * layout, or do nothing.
698      * </ol>
699      *
700      * @param e the change information from the associated document
701      * @param a the current allocation of the view
702      * @param f the factory to use to rebuild if the view has children
703      * @see View#insertUpdate
704      */

705     public void insertUpdate(DocumentEvent e, Shape a, ViewFactory JavaDoc f) {
706     if (getViewCount() > 0) {
707         Element JavaDoc elem = getElement();
708         DocumentEvent.ElementChange ec = e.getChange(elem);
709         if (ec != null) {
710         if (! updateChildren(ec, e, f)) {
711             // don't consider the element changes they
712
// are for a view further down.
713
ec = null;
714         }
715         }
716         forwardUpdate(ec, e, a, f);
717         updateLayout(ec, e, a);
718     }
719     }
720
721     /**
722      * Gives notification that something was removed from the document
723      * in a location that this view is responsible for.
724      * To reduce the burden to subclasses, this functionality is
725      * spread out into the following calls that subclasses can
726      * reimplement:
727      * <ol>
728      * <li><a HREF="#updateChildren">updateChildren</a> is called
729      * if there were any changes to the element this view is
730      * responsible for. If this view has child views that are
731      * represent the child elements, then this method should do
732      * whatever is necessary to make sure the child views correctly
733      * represent the model.
734      * <li><a HREF="#forwardUpdate">forwardUpdate</a> is called
735      * to forward the DocumentEvent to the appropriate child views.
736      * <li><a HREF="#updateLayout">updateLayout</a> is called to
737      * give the view a chance to either repair its layout, to reschedule
738      * layout, or do nothing.
739      * </ol>
740      *
741      * @param e the change information from the associated document
742      * @param a the current allocation of the view
743      * @param f the factory to use to rebuild if the view has children
744      * @see View#removeUpdate
745      */

746     public void removeUpdate(DocumentEvent e, Shape a, ViewFactory JavaDoc f) {
747     if (getViewCount() > 0) {
748         Element JavaDoc elem = getElement();
749         DocumentEvent.ElementChange ec = e.getChange(elem);
750         if (ec != null) {
751         if (! updateChildren(ec, e, f)) {
752             // don't consider the element changes they
753
// are for a view further down.
754
ec = null;
755         }
756         }
757         forwardUpdate(ec, e, a, f);
758         updateLayout(ec, e, a);
759     }
760     }
761
762     /**
763      * Gives notification from the document that attributes were changed
764      * in a location that this view is responsible for.
765      * To reduce the burden to subclasses, this functionality is
766      * spread out into the following calls that subclasses can
767      * reimplement:
768      * <ol>
769      * <li><a HREF="#updateChildren">updateChildren</a> is called
770      * if there were any changes to the element this view is
771      * responsible for. If this view has child views that are
772      * represent the child elements, then this method should do
773      * whatever is necessary to make sure the child views correctly
774      * represent the model.
775      * <li><a HREF="#forwardUpdate">forwardUpdate</a> is called
776      * to forward the DocumentEvent to the appropriate child views.
777      * <li><a HREF="#updateLayout">updateLayout</a> is called to
778      * give the view a chance to either repair its layout, to reschedule
779      * layout, or do nothing.
780      * </ol>
781      *
782      * @param e the change information from the associated document
783      * @param a the current allocation of the view
784      * @param f the factory to use to rebuild if the view has children
785      * @see View#changedUpdate
786      */

787     public void changedUpdate(DocumentEvent e, Shape a, ViewFactory JavaDoc f) {
788     if (getViewCount() > 0) {
789         Element JavaDoc elem = getElement();
790         DocumentEvent.ElementChange ec = e.getChange(elem);
791         if (ec != null) {
792         if (! updateChildren(ec, e, f)) {
793             // don't consider the element changes they
794
// are for a view further down.
795
ec = null;
796         }
797         }
798         forwardUpdate(ec, e, a, f);
799         updateLayout(ec, e, a);
800     }
801     }
802
803     /**
804      * Fetches the model associated with the view.
805      *
806      * @return the view model, <code>null</code> if none
807      * @see View#getDocument
808      */

809     public Document JavaDoc getDocument() {
810     return elem.getDocument();
811     }
812
813     /**
814      * Fetches the portion of the model for which this view is
815      * responsible.
816      *
817      * @return the starting offset into the model >= 0
818      * @see View#getStartOffset
819      */

820     public int getStartOffset() {
821     return elem.getStartOffset();
822     }
823
824     /**
825      * Fetches the portion of the model for which this view is
826      * responsible.
827      *
828      * @return the ending offset into the model >= 0
829      * @see View#getEndOffset
830      */

831     public int getEndOffset() {
832     return elem.getEndOffset();
833     }
834
835     /**
836      * Fetches the structural portion of the subject that this
837      * view is mapped to. The view may not be responsible for the
838      * entire portion of the element.
839      *
840      * @return the subject
841      * @see View#getElement
842      */

843     public Element JavaDoc getElement() {
844     return elem;
845     }
846
847     /**
848      * Fetch a <code>Graphics</code> for rendering.
849      * This can be used to determine
850      * font characteristics, and will be different for a print view
851      * than a component view.
852      *
853      * @return a <code>Graphics</code> object for rendering
854      * @since 1.3
855      */

856     public Graphics getGraphics() {
857     // PENDING(prinz) this is a temporary implementation
858
Component c = getContainer();
859     return c.getGraphics();
860     }
861
862     /**
863      * Fetches the attributes to use when rendering. By default
864      * this simply returns the attributes of the associated element.
865      * This method should be used rather than using the element
866      * directly to obtain access to the attributes to allow
867      * view-specific attributes to be mixed in or to allow the
868      * view to have view-specific conversion of attributes by
869      * subclasses.
870      * Each view should document what attributes it recognizes
871      * for the purpose of rendering or layout, and should always
872      * access them through the <code>AttributeSet</code> returned
873      * by this method.
874      */

875     public AttributeSet JavaDoc getAttributes() {
876     return elem.getAttributes();
877     }
878
879     /**
880      * Tries to break this view on the given axis. This is
881      * called by views that try to do formatting of their
882      * children. For example, a view of a paragraph will
883      * typically try to place its children into row and
884      * views representing chunks of text can sometimes be
885      * broken down into smaller pieces.
886      * <p>
887      * This is implemented to return the view itself, which
888      * represents the default behavior on not being
889      * breakable. If the view does support breaking, the
890      * starting offset of the view returned should be the
891      * given offset, and the end offset should be less than
892      * or equal to the end offset of the view being broken.
893      *
894      * @param axis may be either <code>View.X_AXIS</code> or
895      * <code>View.Y_AXIS</code>
896      * @param offset the location in the document model
897      * that a broken fragment would occupy >= 0. This
898      * would be the starting offset of the fragment
899      * returned
900      * @param pos the position along the axis that the
901      * broken view would occupy >= 0. This may be useful for
902      * things like tab calculations
903      * @param len specifies the distance along the axis
904      * where a potential break is desired >= 0
905      * @return the fragment of the view that represents the
906      * given span, if the view can be broken. If the view
907      * doesn't support breaking behavior, the view itself is
908      * returned.
909      * @see ParagraphView
910      */

911     public View JavaDoc breakView(int axis, int offset, float pos, float len) {
912     return this;
913     }
914
915     /**
916      * Creates a view that represents a portion of the element.
917      * This is potentially useful during formatting operations
918      * for taking measurements of fragments of the view. If
919      * the view doesn't support fragmenting (the default), it
920      * should return itself.
921      *
922      * @param p0 the starting offset >= 0. This should be a value
923      * greater or equal to the element starting offset and
924      * less than the element ending offset.
925      * @param p1 the ending offset > p0. This should be a value
926      * less than or equal to the elements end offset and
927      * greater than the elements starting offset.
928      * @return the view fragment, or itself if the view doesn't
929      * support breaking into fragments
930      * @see LabelView
931      */

932     public View JavaDoc createFragment(int p0, int p1) {
933     return this;
934     }
935
936     /**
937      * Determines how attractive a break opportunity in
938      * this view is. This can be used for determining which
939      * view is the most attractive to call <code>breakView</code>
940      * on in the process of formatting. A view that represents
941      * text that has whitespace in it might be more attractive
942      * than a view that has no whitespace, for example. The
943      * higher the weight, the more attractive the break. A
944      * value equal to or lower than <code>BadBreakWeight</code>
945      * should not be considered for a break. A value greater
946      * than or equal to <code>ForcedBreakWeight</code> should
947      * be broken.
948      * <p>
949      * This is implemented to provide the default behavior
950      * of returning <code>BadBreakWeight</code> unless the length
951      * is greater than the length of the view in which case the
952      * entire view represents the fragment. Unless a view has
953      * been written to support breaking behavior, it is not
954      * attractive to try and break the view. An example of
955      * a view that does support breaking is <code>LabelView</code>.
956      * An example of a view that uses break weight is
957      * <code>ParagraphView</code>.
958      *
959      * @param axis may be either <code>View.X_AXIS</code> or
960      * <code>View.Y_AXIS</code>
961      * @param pos the potential location of the start of the
962      * broken view >= 0. This may be useful for calculating tab
963      * positions
964      * @param len specifies the relative length from <em>pos</em>
965      * where a potential break is desired >= 0
966      * @return the weight, which should be a value between
967      * ForcedBreakWeight and BadBreakWeight
968      * @see LabelView
969      * @see ParagraphView
970      * @see #BadBreakWeight
971      * @see #GoodBreakWeight
972      * @see #ExcellentBreakWeight
973      * @see #ForcedBreakWeight
974      */

975     public int getBreakWeight(int axis, float pos, float len) {
976     if (len > getPreferredSpan(axis)) {
977         return GoodBreakWeight;
978     }
979     return BadBreakWeight;
980     }
981
982     /**
983      * Determines the resizability of the view along the
984      * given axis. A value of 0 or less is not resizable.
985      *
986      * @param axis may be either <code>View.X_AXIS</code> or
987      * <code>View.Y_AXIS</code>
988      * @return the weight
989      */

990     public int getResizeWeight(int axis) {
991     return 0;
992     }
993
994     /**
995      * Sets the size of the view. This should cause
996      * layout of the view along the given axis, if it
997      * has any layout duties.
998      *
999      * @param width the width >= 0
1000     * @param height the height >= 0
1001     */

1002    public void setSize(float width, float height) {
1003    }
1004
1005    /**
1006     * Fetches the container hosting the view. This is useful for
1007     * things like scheduling a repaint, finding out the host
1008     * components font, etc. The default implementation
1009     * of this is to forward the query to the parent view.
1010     *
1011     * @return the container, <code>null</code> if none
1012     */

1013    public Container getContainer() {
1014    View JavaDoc v = getParent();
1015    return (v != null) ? v.getContainer() : null;
1016    }
1017
1018    /**
1019     * Fetches the <code>ViewFactory</code> implementation that is feeding
1020     * the view hierarchy. Normally the views are given this
1021     * as an argument to updates from the model when they
1022     * are most likely to need the factory, but this
1023     * method serves to provide it at other times.
1024     *
1025     * @return the factory, <code>null</code> if none
1026     */

1027    public ViewFactory JavaDoc getViewFactory() {
1028    View JavaDoc v = getParent();
1029    return (v != null) ? v.getViewFactory() : null;
1030    }
1031
1032    /**
1033     * Returns the tooltip text at the specified location. The default
1034     * implementation returns the value from the child View identified by
1035     * the passed in location.
1036     *
1037     * @since 1.4
1038     * @see JTextComponent#getToolTipText
1039     */

1040    public String JavaDoc getToolTipText(float x, float y, Shape allocation) {
1041    int viewIndex = getViewIndex(x, y, allocation);
1042        if (viewIndex >= 0) {
1043            allocation = getChildAllocation(viewIndex, allocation);
1044            Rectangle rect = (allocation instanceof Rectangle) ?
1045                             (Rectangle)allocation : allocation.getBounds();
1046            if (rect.contains(x, y)) {
1047                return getView(viewIndex).getToolTipText(x, y, allocation);
1048            }
1049        }
1050        return null;
1051    }
1052
1053    /**
1054     * Returns the child view index representing the given position in
1055     * the view. This iterates over all the children returning the
1056     * first with a bounds that contains <code>x</code>, <code>y</code>.
1057     *
1058     * @param x the x coordinate
1059     * @param y the y coordinate
1060     * @param allocation current allocation of the View.
1061     * @return index of the view representing the given location, or
1062     * -1 if no view represents that position
1063     * @since 1.4
1064     */

1065    public int getViewIndex(float x, float y, Shape allocation) {
1066    for (int counter = getViewCount() - 1; counter >= 0; counter--) {
1067        Shape childAllocation = getChildAllocation(counter, allocation);
1068
1069            if (childAllocation != null) {
1070                Rectangle rect = (childAllocation instanceof Rectangle) ?
1071                 (Rectangle)childAllocation : allocation.getBounds();
1072
1073                if (rect.contains(x, y)) {
1074                    return counter;
1075                }
1076            }
1077    }
1078    return -1;
1079    }
1080
1081    /**
1082     * Updates the child views in response to receiving notification
1083     * that the model changed, and there is change record for the
1084     * element this view is responsible for. This is implemented
1085     * to assume the child views are directly responsible for the
1086     * child elements of the element this view represents. The
1087     * <code>ViewFactory</code> is used to create child views for each element
1088     * specified as added in the <code>ElementChange</code>, starting at the
1089     * index specified in the given <code>ElementChange</code>. The number of
1090     * child views representing the removed elements specified are
1091     * removed.
1092     *
1093     * @param ec the change information for the element this view
1094     * is responsible for. This should not be <code>null</code> if
1095     * this method gets called
1096     * @param e the change information from the associated document
1097     * @param f the factory to use to build child views
1098     * @return whether or not the child views represent the
1099     * child elements of the element this view is responsible
1100     * for. Some views create children that represent a portion
1101     * of the element they are responsible for, and should return
1102     * false. This information is used to determine if views
1103     * in the range of the added elements should be forwarded to
1104     * or not
1105     * @see #insertUpdate
1106     * @see #removeUpdate
1107     * @see #changedUpdate
1108     * @since 1.3
1109     */

1110    protected boolean updateChildren(DocumentEvent.ElementChange ec,
1111                     DocumentEvent e, ViewFactory JavaDoc f) {
1112    Element JavaDoc[] removedElems = ec.getChildrenRemoved();
1113    Element JavaDoc[] addedElems = ec.getChildrenAdded();
1114    View JavaDoc[] added = null;
1115    if (addedElems != null) {
1116        added = new View JavaDoc[addedElems.length];
1117        for (int i = 0; i < addedElems.length; i++) {
1118        added[i] = f.create(addedElems[i]);
1119        }
1120    }
1121    int nremoved = 0;
1122    int index = ec.getIndex();
1123    if (removedElems != null) {
1124        nremoved = removedElems.length;
1125    }
1126    replace(index, nremoved, added);
1127    return true;
1128    }
1129
1130    /**
1131     * Forwards the given <code>DocumentEvent</code> to the child views
1132     * that need to be notified of the change to the model.
1133     * If there were changes to the element this view is
1134     * responsible for, that should be considered when
1135     * forwarding (i.e. new child views should not get
1136     * notified).
1137     *
1138     * @param ec changes to the element this view is responsible
1139     * for (may be <code>null</code> if there were no changes).
1140     * @param e the change information from the associated document
1141     * @param a the current allocation of the view
1142     * @param f the factory to use to rebuild if the view has children
1143     * @see #insertUpdate
1144     * @see #removeUpdate
1145     * @see #changedUpdate
1146     * @since 1.3
1147     */

1148    protected void forwardUpdate(DocumentEvent.ElementChange ec,
1149                      DocumentEvent e, Shape a, ViewFactory JavaDoc f) {
1150    Element JavaDoc elem = getElement();
1151    int pos = e.getOffset();
1152    int index0 = getViewIndex(pos, Position.Bias.Forward);
1153    if (index0 == -1 && e.getType() == DocumentEvent.EventType.REMOVE &&
1154        pos >= getEndOffset()) {
1155        // Event beyond our offsets. We may have represented this, that is
1156
// the remove may have removed one of our child Elements that
1157
// represented this, so, we should foward to last element.
1158
index0 = getViewCount() - 1;
1159    }
1160    int index1 = index0;
1161    View JavaDoc v = (index0 >= 0) ? getView(index0) : null;
1162    if (v != null) {
1163        if ((v.getStartOffset() == pos) && (pos > 0)) {
1164        // If v is at a boundary, forward the event to the previous
1165
// view too.
1166
index0 = Math.max(index0 - 1, 0);
1167        }
1168    }
1169    if (e.getType() != DocumentEvent.EventType.REMOVE) {
1170        index1 = getViewIndex(pos + e.getLength(), Position.Bias.Forward);
1171        if (index1 < 0) {
1172        index1 = getViewCount() - 1;
1173        }
1174    }
1175    int hole0 = index1 + 1;
1176    int hole1 = hole0;
1177    Element JavaDoc[] addedElems = (ec != null) ? ec.getChildrenAdded() : null;
1178    if ((addedElems != null) && (addedElems.length > 0)) {
1179        hole0 = ec.getIndex();
1180        hole1 = hole0 + addedElems.length - 1;
1181    }
1182
1183    // forward to any view not in the forwarding hole
1184
// formed by added elements (i.e. they will be updated
1185
// by initialization.
1186
index0 = Math.max(index0, 0);
1187    for (int i = index0; i <= index1; i++) {
1188        if (! ((i >= hole0) && (i <= hole1))) {
1189        v = getView(i);
1190        if (v != null) {
1191            Shape childAlloc = getChildAllocation(i, a);
1192            forwardUpdateToView(v, e, childAlloc, f);
1193        }
1194        }
1195    }
1196    }
1197
1198    /**
1199     * Forwards the <code>DocumentEvent</code> to the give child view. This
1200     * simply messages the view with a call to <code>insertUpdate</code>,
1201     * <code>removeUpdate</code>, or <code>changedUpdate</code> depending
1202     * upon the type of the event. This is called by
1203     * <a HREF="#forwardUpdate">forwardUpdate</a> to forward
1204     * the event to children that need it.
1205     *
1206     * @param v the child view to forward the event to
1207     * @param e the change information from the associated document
1208     * @param a the current allocation of the view
1209     * @param f the factory to use to rebuild if the view has children
1210     * @see #forwardUpdate
1211     * @since 1.3
1212     */

1213    protected void forwardUpdateToView(View JavaDoc v, DocumentEvent e,
1214                       Shape a, ViewFactory JavaDoc f) {
1215    DocumentEvent.EventType type = e.getType();
1216    if (type == DocumentEvent.EventType.INSERT) {
1217        v.insertUpdate(e, a, f);
1218    } else if (type == DocumentEvent.EventType.REMOVE) {
1219        v.removeUpdate(e, a, f);
1220    } else {
1221        v.changedUpdate(e, a, f);
1222    }
1223    }
1224
1225    /**
1226     * Updates the layout in response to receiving notification of
1227     * change from the model. This is implemented to call
1228     * <code>preferenceChanged</code> to reschedule a new layout
1229     * if the <code>ElementChange</code> record is not <code>null</code>.
1230     *
1231     * @param ec changes to the element this view is responsible
1232     * for (may be <code>null</code> if there were no changes)
1233     * @param e the change information from the associated document
1234     * @param a the current allocation of the view
1235     * @see #insertUpdate
1236     * @see #removeUpdate
1237     * @see #changedUpdate
1238     * @since 1.3
1239     */

1240    protected void updateLayout(DocumentEvent.ElementChange ec,
1241                    DocumentEvent e, Shape a) {
1242    if ((ec != null) && (a != null)) {
1243        // should damage more intelligently
1244
preferenceChanged(null, true, true);
1245        Container host = getContainer();
1246        if (host != null) {
1247        host.repaint();
1248        }
1249    }
1250    }
1251
1252    /**
1253     * The weight to indicate a view is a bad break
1254     * opportunity for the purpose of formatting. This
1255     * value indicates that no attempt should be made to
1256     * break the view into fragments as the view has
1257     * not been written to support fragmenting.
1258     *
1259     * @see #getBreakWeight
1260     * @see #GoodBreakWeight
1261     * @see #ExcellentBreakWeight
1262     * @see #ForcedBreakWeight
1263     */

1264    public static final int BadBreakWeight = 0;
1265
1266    /**
1267     * The weight to indicate a view supports breaking,
1268     * but better opportunities probably exist.
1269     *
1270     * @see #getBreakWeight
1271     * @see #BadBreakWeight
1272     * @see #ExcellentBreakWeight
1273     * @see #ForcedBreakWeight
1274     */

1275    public static final int GoodBreakWeight = 1000;
1276
1277    /**
1278     * The weight to indicate a view supports breaking,
1279     * and this represents a very attractive place to
1280     * break.
1281     *
1282     * @see #getBreakWeight
1283     * @see #BadBreakWeight
1284     * @see #GoodBreakWeight
1285     * @see #ForcedBreakWeight
1286     */

1287    public static final int ExcellentBreakWeight = 2000;
1288
1289    /**
1290     * The weight to indicate a view supports breaking,
1291     * and must be broken to be represented properly
1292     * when placed in a view that formats its children
1293     * by breaking them.
1294     *
1295     * @see #getBreakWeight
1296     * @see #BadBreakWeight
1297     * @see #GoodBreakWeight
1298     * @see #ExcellentBreakWeight
1299     */

1300    public static final int ForcedBreakWeight = 3000;
1301
1302    /**
1303     * Axis for format/break operations.
1304     */

1305    public static final int X_AXIS = HORIZONTAL;
1306
1307    /**
1308     * Axis for format/break operations.
1309     */

1310    public static final int Y_AXIS = VERTICAL;
1311
1312    /**
1313     * Provides a mapping from the document model coordinate space
1314     * to the coordinate space of the view mapped to it. This is
1315     * implemented to default the bias to <code>Position.Bias.Forward</code>
1316     * which was previously implied.
1317     *
1318     * @param pos the position to convert >= 0
1319     * @param a the allocated region in which to render
1320     * @return the bounding box of the given position is returned
1321     * @exception BadLocationException if the given position does
1322     * not represent a valid location in the associated document
1323     * @see View#modelToView
1324     * @deprecated
1325     */

1326    @Deprecated JavaDoc
1327    public Shape modelToView(int pos, Shape a) throws BadLocationException JavaDoc {
1328    return modelToView(pos, a, Position.Bias.Forward);
1329    }
1330
1331
1332    /**
1333     * Provides a mapping from the view coordinate space to the logical
1334     * coordinate space of the model.
1335     *
1336     * @param x the X coordinate >= 0
1337     * @param y the Y coordinate >= 0
1338     * @param a the allocated region in which to render
1339     * @return the location within the model that best represents the
1340     * given point in the view >= 0
1341     * @see View#viewToModel
1342     * @deprecated
1343     */

1344    @Deprecated JavaDoc
1345    public int viewToModel(float x, float y, Shape a) {
1346    sharedBiasReturn[0] = Position.Bias.Forward;
1347    return viewToModel(x, y, a, sharedBiasReturn);
1348    }
1349
1350    // static argument available for viewToModel calls since only
1351
// one thread at a time may call this method.
1352
static final Position.Bias JavaDoc[] sharedBiasReturn = new Position.Bias JavaDoc[1];
1353
1354    private View JavaDoc parent;
1355    private Element JavaDoc elem;
1356
1357};
1358
1359
Popular Tags