13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package javax.swing.text;
26
27 import java.awt.*;
28 import javax.swing.SwingConstants;
29 import javax.swing.event.*;
30
31 /**
32 * <p>
33 * A very important part of the text package is the <code>View</code> class.
34 * As the name suggests it represents a view of the text model,
35 * or a piece of the text model.
36 * It is this class that is responsible for the look of the text component.
37 * The view is not intended to be some completely new thing that one must
38 * learn, but rather is much like a lightweight component.
39 * <p>
40 By default, a view is very light. It contains a reference to the parent
41 view from which it can fetch many things without holding state, and it
42 contains a reference to a portion of the model (<code>Element</code>).
43 A view does not
44 have to exactly represent an element in the model, that is simply a typical
45 and therefore convenient mapping. A view can alternatively maintain a couple
46 of Position objects to maintain its location in the model (i.e. represent
47 a fragment of an element). This is typically the result of formatting where
48 views have been broken down into pieces. The convenience of a substantial
49 relationship to the element makes it easier to build factories to produce the
50 views, and makes it easier to keep track of the view pieces as the model is
51 changed and the view must be changed to reflect the model. Simple views
52 therefore represent an Element directly and complex views do not.
53 <p>
54 A view has the following responsibilities:
55 <dl>
56
57 <dt><b>Participate in layout.</b>
58 <dd>
59 <p>The view has a <code>setSize</code> method which is like
60 <code>doLayout</code> and <code>setSize</code> in <code>Component</code> combined.
61 The view has a <code>preferenceChanged</code> method which is
62 like <code>invalidate</code> in <code>Component</code> except that one can
63 invalidate just one axis
64 and the child requesting the change is identified.
65 <p>A View expresses the size that it would like to be in terms of three
66 values, a minimum, a preferred, and a maximum span. Layout in a view is
67 can be done independently upon each axis. For a properly functioning View
68 implementation, the minimum span will be <= the preferred span which in turn
69 will be <= the maximum span.
70 </p>
71 <p style="text-align:center"><img src="doc-files/View-flexibility.jpg"
72 alt="The above text describes this graphic.">
73 <p>The minimum set of methods for layout are:
74 <ul>
75 <li>{@link #getMinimumSpan(int) getMinimumSpan}
76 <li>{@link #getPreferredSpan(int) getPreferredSpan}
77 <li>{@link #getMaximumSpan(int) getMaximumSpan}
78 <li>{@link #getAlignment(int) getAlignment}
79 <li>{@link #preferenceChanged(javax.swing.text.View, boolean, boolean) preferenceChanged}
80 <li>{@link #setSize(float, float) setSize}
81 </ul>
82
83 <p>The <code>setSize</code> method should be prepared to be called a number of times
84 (i.e. It may be called even if the size didn't change).
85 The <code>setSize</code> method
86 is generally called to make sure the View layout is complete prior to trying
87 to perform an operation on it that requires an up-to-date layout. A view's
88 size should <em>always</em> be set to a value within the minimum and maximum
89 span specified by that view. Additionally, the view must always call the
90 <code>preferenceChanged</code> method on the parent if it has changed the
91 values for the
92 layout it would like, and expects the parent to honor. The parent View is
93 not required to recognize a change until the <code>preferenceChanged</code>
94 has been sent.
95 This allows parent View implementations to cache the child requirements if
96 desired. The calling sequence looks something like the following:
97 </p>
98 <p style="text-align:center">
99 <img src="doc-files/View-layout.jpg"
100 alt="Sample calling sequence between parent view and child view:
101 setSize, getMinimum, getPreferred, getMaximum, getAlignment, setSize">
102 <p>The exact calling sequence is up to the layout functionality of
103 the parent view (if the view has any children). The view may collect
104 the preferences of the children prior to determining what it will give
105 each child, or it might iteratively update the children one at a time.
106 </p>
107
108 <dt><b>Render a portion of the model.</b>
109 <dd>
110 <p>This is done in the paint method, which is pretty much like a component
111 paint method. Views are expected to potentially populate a fairly large
112 tree. A <code>View</code> has the following semantics for rendering:
113 </p>
114 <ul>
115 <li>The view gets its allocation from the parent at paint time, so it
116 must be prepared to redo layout if the allocated area is different from
117 what it is prepared to deal with.
118 <li>The coordinate system is the same as the hosting <code>Component</code>
119 (i.e. the <code>Component</code> returned by the
120 {@link #getContainer getContainer} method).
121 This means a child view lives in the same coordinate system as the parent
122 view unless the parent has explicitly changed the coordinate system.
123 To schedule itself to be repainted a view can call repaint on the hosting
124 <code>Component</code>.
125 <li>The default is to <em>not clip</em> the children. It is more efficient
126 to allow a view to clip only if it really feels it needs clipping.
127 <li>The <code>Graphics</code> object given is not initialized in any way.
128 A view should set any settings needed.
129 <li>A <code>View</code> is inherently transparent. While a view may render into its
130 entire allocation, typically a view does not. Rendering is performed by
131 traversing down the tree of <code>View</code> implementations.
132 Each <code>View</code> is responsible
133 for rendering its children. This behavior is depended upon for thread
134 safety. While view implementations do not necessarily have to be implemented
135 with thread safety in mind, other view implementations that do make use of
136 concurrency can depend upon a tree traversal to guarantee thread safety.
137 <li>The order of views relative to the model is up to the implementation.
138 Although child views will typically be arranged in the same order that they
139 occur in the model, they may be visually arranged in an entirely different
140 order. View implementations may have Z-Order associated with them if the
141 children are overlapping.
142 </ul>
143 <p>The methods for rendering are:
144 <ul>
145 <li>{@link #paint(java.awt.Graphics, java.awt.Shape) paint}
146 </ul>
147
148 <dt><b>Translate between the model and view coordinate systems.</b>
149 <dd>
150 <p>Because the view objects are produced from a factory and therefore cannot
151 necessarily be counted upon to be in a particular pattern, one must be able
152 to perform translation to properly locate spatial representation of the model.
153 The methods for doing this are:
154 <ul>
155 <li>{@link #modelToView(int, javax.swing.text.Position.Bias, int, javax.swing.text.Position.Bias, java.awt.Shape) modelToView}
156 <li>{@link #viewToModel(float, float, java.awt.Shape, javax.swing.text.Position.Bias[]) viewToModel}
157 <li>{@link #getDocument() getDocument}
158 <li>{@link #getElement() getElement}
159 <li>{@link #getStartOffset() getStartOffset}
160 <li>{@link #getEndOffset() getEndOffset}
161 </ul>
162 <p>The layout must be valid prior to attempting to make the translation.
163 The translation is not valid, and must not be attempted while changes
164 are being broadcasted from the model via a <code>DocumentEvent</code>.
165 </p>
166
167 <dt><b>Respond to changes from the model.</b>
168 <dd>
169 <p>If the overall view is represented by many pieces (which is the best situation
170 if one want to be able to change the view and write the least amount of new code),
171 it would be impractical to have a huge number of <code>DocumentListener</code>s.
172 If each
173 view listened to the model, only a few would actually be interested in the
174 changes broadcasted at any given time. Since the model has no knowledge of
175 views, it has no way to filter the broadcast of change information. The view
176 hierarchy itself is instead responsible for propagating the change information.
177 At any level in the view hierarchy, that view knows enough about its children to
178 best distribute the change information further. Changes are therefore broadcasted
179 starting from the root of the view hierarchy.
180 The methods for doing this are:
181 <ul>
182 <li>{@link #insertUpdate insertUpdate}
183 <li>{@link #removeUpdate removeUpdate}
184 <li>{@link #changedUpdate changedUpdate}
185 </ul>
186 </dl>
187 *
188 * @author Timothy Prinzing
189 */
190 public abstract class View implements SwingConstants {
191
192 /**
193 * Creates a new <code>View</code> object.
194 *
195 * @param elem the <code>Element</code> to represent
196 */
197 public View(Element elem) {
198 this.elem = elem;
199 }
200
201 /**
202 * Returns the parent of the view.
203 *
204 * @return the parent, or <code>null</code> if none exists
205 */
206 public View getParent() {
207 return parent;
208 }
209
210 /**
211 * Returns a boolean that indicates whether
212 * the view is visible or not. By default
213 * all views are visible.
214 *
215 * @return always returns true
216 */
217 public boolean isVisible() {
218 return true;
219 }
220
221
222 /**
223 * Determines the preferred span for this view along an
224 * axis.
225 *
226 * @param axis may be either <code>View.X_AXIS</code> or
227 * <code>View.Y_AXIS</code>
228 * @return the span the view would like to be rendered into.
229 * Typically the view is told to render into the span
230 * that is returned, although there is no guarantee.
231 * The parent may choose to resize or break the view
232 * @see View#getPreferredSpan
233 */
234 public abstract float getPreferredSpan(int axis);
235
236 /**
237 * Determines the minimum span for this view along an
238 * axis.
239 *
240 * @param axis may be either <code>View.X_AXIS</code> or
241 * <code>View.Y_AXIS</code>
242 * @return the minimum span the view can be rendered into
243 * @see View#getPreferredSpan
244 */
245 public float getMinimumSpan(int axis) {
246 int w = getResizeWeight(axis);
247 if (w == 0) {
248 // can't resize
249 return getPreferredSpan(axis);
250 }
251 return 0;
252 }
253
254 /**
255 * Determines the maximum span for this view along an
256 * axis.
257 *
258 * @param axis may be either <code>View.X_AXIS</code> or
259 * <code>View.Y_AXIS</code>
260 * @return the maximum span the view can be rendered into
261 * @see View#getPreferredSpan
262 */
263 public float getMaximumSpan(int axis) {
264 int w = getResizeWeight(axis);
265 if (w == 0) {
266 // can't resize
267 return getPreferredSpan(axis);
268 }
269 return Integer.MAX_VALUE;
270 }
271
272 /**
273 * Child views can call this on the parent to indicate that
274 * the preference has changed and should be reconsidered
275 * for layout. By default this just propagates upward to
276 * the next parent. The root view will call
277 * <code>revalidate</code> on the associated text component.
278 *
279 * @param child the child view
280 * @param width true if the width preference has changed
281 * @param height true if the height preference has changed
282 * @see javax.swing.JComponent#revalidate
283 */
284 public void preferenceChanged(View child, boolean width, boolean height) {
285 View parent = getParent();
286 if (parent != null) {
287 parent.preferenceChanged(this, width, height);
288 }
289 }
290
291 /**
292 * Determines the desired alignment for this view along an
293 * axis. The desired alignment is returned. This should be
294 * a value >= 0.0 and <= 1.0, where 0 indicates alignment at
295 * the origin and 1.0 indicates alignment to the full span
296 * away from the origin. An alignment of 0.5 would be the
297 * center of the view.
298 *
299 * @param axis may be either <code>View.X_AXIS</code> or
300 * <code>View.Y_AXIS</code>
301 * @return the value 0.5
302 */
303 public float getAlignment(int axis) {
304 return 0.5f;
305 }
306
307 /**
308 * Renders using the given rendering surface and area on that
309 * surface. The view may need to do layout and create child
310 * views to enable itself to render into the given allocation.
311 *
312 * @param g the rendering surface to use
313 * @param allocation the allocated region to render into
314 */
315 public abstract void paint(Graphics g, Shape allocation);
316
317 /**
318 * Establishes the parent view for this view. This is
319 * guaranteed to be called before any other methods if the
320 * parent view is functioning properly. This is also
321 * the last method called, since it is called to indicate
322 * the view has been removed from the hierarchy as
323 * well. When this method is called to set the parent to
324 * null, this method does the same for each of its children,
325 * propagating the notification that they have been
326 * disconnected from the view tree. If this is
327 * reimplemented, <code>super.setParent()</code> should
328 * be called.
329 *
330 * @param parent the new parent, or <code>null</code> if the view is
331 * being removed from a parent
332 */
333 public void setParent(View parent) {
334 // if the parent is null then propogate down the view tree
335 if (parent == null) {
336 for (int i = 0; i < getViewCount(); i++) {
337 if (getView(i).getParent() == this) {
338 // in FlowView.java view might be referenced
339 // from two super-views as a child. see logicalView
340 getView(i).setParent(null);
341 }
342 }
343 }
344 this.parent = parent;
345 }
346
347 /**
348 * Returns the number of views in this view. Since
349 * the default is to not be a composite view this
350 * returns 0.
351 *
352 * @return the number of views >= 0
353 * @see View#getViewCount
354 */
355 public int getViewCount() {
356 return 0;
357 }
358
359 /**
360 * Gets the <i>n</i>th child view. Since there are no
361 * children by default, this returns <code>null</code>.
362 *
363 * @param n the number of the view to get, >= 0 && < getViewCount()
364 * @return the view
365 */
366 public View getView(int n) {
367 return null;
368 }
369
370
371 /**
372 * Removes all of the children. This is a convenience
373 * call to <code>replace</code>.
374 *
375 * @since 1.3
376 */
377 public void removeAll() {
378 replace(0, getViewCount(), null);
379 }
380
381 /**
382 * Removes one of the children at the given position.
383 * This is a convenience call to <code>replace</code>.
384 * @param i the position
385 * @since 1.3
386 */
387 public void remove(int i) {
388 replace(i, 1, null);
389 }
390
391 /**
392 * Inserts a single child view. This is a convenience
393 * call to <code>replace</code>.
394 *
395 * @param offs the offset of the view to insert before >= 0
396 * @param v the view
397 * @see #replace
398 * @since 1.3
399 */
400 public void insert(int offs, View v) {
401 View[] one = new View[1];
402 one[0] = v;
403 replace(offs, 0, one);
404 }
405
406 /**
407 * Appends a single child view. This is a convenience
408 * call to <code>replace</code>.
409 *
410 * @param v the view
411 * @see #replace
412 * @since 1.3
413 */
414 public void append(View v) {
415 View[] one = new View[1];
416 one[0] = v;
417 replace(getViewCount(), 0, one);
418 }
419
420 /**
421 * Replaces child views. If there are no views to remove
422 * this acts as an insert. If there are no views to
423 * add this acts as a remove. Views being removed will
424 * have the parent set to <code>null</code>, and the internal reference
425 * to them removed so that they can be garbage collected.
426 * This is implemented to do nothing, because by default
427 * a view has no children.
428 *
429 * @param offset the starting index into the child views to insert
430 * the new views. This should be a value >= 0 and <= getViewCount
431 * @param length the number of existing child views to remove
432 * This should be a value >= 0 and <= (getViewCount() - offset).
433 * @param views the child views to add. This value can be
434 * <code>null</code> to indicate no children are being added
435 * (useful to remove).
436 * @since 1.3
437 */
438 public void replace(int offset, int length, View[] views) {
439 }
440
441 /**
442 * Returns the child view index representing the given position in
443 * the model. By default a view has no children so this is implemented
444 * to return -1 to indicate there is no valid child index for any
445 * position.
446 *
447 * @param pos the position >= 0
448 * @param b the bias
449 * @return index of the view representing the given position, or
450 * -1 if no view represents that position
451 * @since 1.3
452 */
453 public int getViewIndex(int pos, Position.Bias b) {
454 return -1;
455 }
456
457 /**
458 * Fetches the allocation for the given child view.
459 * This enables finding out where various views
460 * are located, without assuming how the views store
461 * their location. This returns <code>null</code> since the
462 * default is to not have any child views.
463 *
464 * @param index the index of the child, >= 0 && <
465 * <code>getViewCount()</code>
466 * @param a the allocation to this view
467 * @return the allocation to the child
468 */
469 public Shape getChildAllocation(int index, Shape a) {
470 return null;
471 }
472
473 /**
474 * Provides a way to determine the next visually represented model
475 * location at which one might place a caret.
476 * Some views may not be visible,
477 * they might not be in the same order found in the model, or they just
478 * might not allow access to some of the locations in the model.
479 * This method enables specifying a position to convert
480 * within the range of >=0. If the value is -1, a position
481 * will be calculated automatically. If the value < -1,
482 * the {@code BadLocationException} will be thrown.
483 *
484 * @param pos the position to convert
485 * @param b the bias
486 * @param a the allocated region in which to render
487 * @param direction the direction from the current position that can
488 * be thought of as the arrow keys typically found on a keyboard.
489 * This will be one of the following values:
490 * <ul>
491 * <li>SwingConstants.WEST
492 * <li>SwingConstants.EAST
493 * <li>SwingConstants.NORTH
494 * <li>SwingConstants.SOUTH
495 * </ul>
496 * @param biasRet the returned bias
497 * @return the location within the model that best represents the next
498 * location visual position
499 * @exception BadLocationException the given position is not a valid
500 * position within the document
501 * @exception IllegalArgumentException if <code>direction</code>
502 * doesn't have one of the legal values above
503 */
504 public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a,
505 int direction, Position.Bias[] biasRet)
506 throws BadLocationException {
507 if (pos < -1 || pos > getDocument().getLength()) {
508 // -1 is a reserved value, see the code below
509 throw new BadLocationException("Invalid position", pos);
510 }
511
512 biasRet[0] = Position.Bias.Forward;
513 switch (direction) {
514 case NORTH:
515 case SOUTH:
516 {
517 if (pos == -1) {
518 pos = (direction == NORTH) ? Math.max(0, getEndOffset() - 1) :
519 getStartOffset();
520 break;
521 }
560 }
561 else {
562 pos = Math.min(pos + 1, getDocument().getLength());
563 }
564 break;
565 default:
566 throw new IllegalArgumentException("Bad direction: " + direction);
567 }
568 return pos;
569 }
570
571 /**
572 * Provides a mapping, for a given character,
573 * from the document model coordinate space
574 * to the view coordinate space.
575 *
576 * @param pos the position of the desired character (>=0)
577 * @param a the area of the view, which encompasses the requested character
578 * @param b the bias toward the previous character or the
579 * next character represented by the offset, in case the
580 * position is a boundary of two views; <code>b</code> will have one
581 * of these values:
582 * <ul>
583 * <li> <code>Position.Bias.Forward</code>
584 * <li> <code>Position.Bias.Backward</code>
585 * </ul>
586 * @return the bounding box, in view coordinate space,
587 * of the character at the specified position
588 * @exception BadLocationException if the specified position does
589 * not represent a valid location in the associated document
590 * @exception IllegalArgumentException if <code>b</code> is not one of the
591 * legal <code>Position.Bias</code> values listed above
592 * @see View#viewToModel
593 */
594 public abstract Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException;
595
596 /**
597 * Provides a mapping, for a given region,
598 * from the document model coordinate space
599 * to the view coordinate space. The specified region is
600 * created as a union of the first and last character positions.
601 *
602 * @param p0 the position of the first character (>=0)
603 * @param b0 the bias of the first character position,
604 * toward the previous character or the
605 * next character represented by the offset, in case the
606 * position is a boundary of two views; <code>b0</code> will have one
607 * of these values:
608 * <ul style="list-style-type:none">
609 * <li> <code>Position.Bias.Forward</code>
610 * <li> <code>Position.Bias.Backward</code>
611 * </ul>
612 * @param p1 the position of the last character (>=0)
613 * @param b1 the bias for the second character position, defined
614 * one of the legal values shown above
615 * @param a the area of the view, which encompasses the requested region
616 * @return the bounding box which is a union of the region specified
617 * by the first and last character positions
618 * @exception BadLocationException if the given position does
619 * not represent a valid location in the associated document
620 * @exception IllegalArgumentException if <code>b0</code> or
621 * <code>b1</code> are not one of the
622 * legal <code>Position.Bias</code> values listed above
623 * @see View#viewToModel
624 */
625 public Shape modelToView(int p0, Position.Bias b0, int p1, Position.Bias b1, Shape a) throws BadLocationException {
626 Shape s0 = modelToView(p0, a, b0);
627 Shape s1;
628 if (p1 == getEndOffset()) {
629 try {
630 s1 = modelToView(p1, a, b1);
631 } catch (BadLocationException ble) {
632 s1 = null;
633 }
634 if (s1 == null) {
635 // Assume extends left to right.
636 Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
637 a.getBounds();
638 s1 = new Rectangle(alloc.x + alloc.width - 1, alloc.y,
639 1, alloc.height);
640 }
641 }
642 else {
643 s1 = modelToView(p1, a, b1);
644 }
645 Rectangle r0 = s0.getBounds();
646 Rectangle r1 = (s1 instanceof Rectangle) ? (Rectangle) s1 :
647 s1.getBounds();
648 if (r0.y != r1.y) {
649 // If it spans lines, force it to be the width of the view.
650 Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
651 a.getBounds();
652 r0.x = alloc.x;
653 r0.width = alloc.width;
654 }
655 r0.add(r1);
656 return r0;
657 }
658
659 /**
660 * Provides a mapping from the view coordinate space to the logical
661 * coordinate space of the model. The <code>biasReturn</code>
662 * argument will be filled in to indicate that the point given is
663 * closer to the next character in the model or the previous
664 * character in the model.
665 *
666 * @param x the X coordinate >= 0
667 * @param y the Y coordinate >= 0
668 * @param a the allocated region in which to render
669 * @param biasReturn the returned bias
670 * @return the location within the model that best represents the
671 * given point in the view >= 0. The <code>biasReturn</code>
672 * argument will be
673 * filled in to indicate that the point given is closer to the next
674 * character in the model or the previous character in the model.
675 */
676 public abstract int viewToModel(float x, float y, Shape a, Position.Bias[] biasReturn);
677
678 /**
679 * Gives notification that something was inserted into
680 * the document in a location that this view is responsible for.
681 * To reduce the burden to subclasses, this functionality is
682 * spread out into the following calls that subclasses can
683 * reimplement:
684 * <ol>
685 * <li>{@link #updateChildren updateChildren} is called
686 * if there were any changes to the element this view is
687 * responsible for. If this view has child views that are
688 * represent the child elements, then this method should do
689 * whatever is necessary to make sure the child views correctly
690 * represent the model.
691 * <li>{@link #forwardUpdate forwardUpdate} is called
784 */
785 public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
786 if (getViewCount() > 0) {
787 Element elem = getElement();
788 DocumentEvent.ElementChange ec = e.getChange(elem);
789 if (ec != null) {
790 if (! updateChildren(ec, e, f)) {
791 // don't consider the element changes they
792 // are for a view further down.
793 ec = null;
794 }
795 }
796 forwardUpdate(ec, e, a, f);
797 updateLayout(ec, e, a);
798 }
799 }
800
801 /**
802 * Fetches the model associated with the view.
803 *
804 * @return the view model, <code>null</code> if none
805 * @see View#getDocument
806 */
807 public Document getDocument() {
808 return elem.getDocument();
809 }
810
811 /**
812 * Fetches the portion of the model for which this view is
813 * responsible.
814 *
815 * @return the starting offset into the model >= 0
816 * @see View#getStartOffset
817 */
818 public int getStartOffset() {
819 return elem.getStartOffset();
820 }
821
822 /**
823 * Fetches the portion of the model for which this view is
824 * responsible.
826 * @return the ending offset into the model >= 0
827 * @see View#getEndOffset
828 */
829 public int getEndOffset() {
830 return elem.getEndOffset();
831 }
832
833 /**
834 * Fetches the structural portion of the subject that this
835 * view is mapped to. The view may not be responsible for the
836 * entire portion of the element.
837 *
838 * @return the subject
839 * @see View#getElement
840 */
841 public Element getElement() {
842 return elem;
843 }
844
845 /**
846 * Fetch a <code>Graphics</code> for rendering.
847 * This can be used to determine
848 * font characteristics, and will be different for a print view
849 * than a component view.
850 *
851 * @return a <code>Graphics</code> object for rendering
852 * @since 1.3
853 */
854 public Graphics getGraphics() {
855 // PENDING(prinz) this is a temporary implementation
856 Component c = getContainer();
857 return c.getGraphics();
858 }
859
860 /**
861 * Fetches the attributes to use when rendering. By default
862 * this simply returns the attributes of the associated element.
863 * This method should be used rather than using the element
864 * directly to obtain access to the attributes to allow
865 * view-specific attributes to be mixed in or to allow the
866 * view to have view-specific conversion of attributes by
867 * subclasses.
868 * Each view should document what attributes it recognizes
869 * for the purpose of rendering or layout, and should always
870 * access them through the <code>AttributeSet</code> returned
871 * by this method.
872 * @return the attributes to use when rendering
873 */
874 public AttributeSet getAttributes() {
875 return elem.getAttributes();
876 }
877
878 /**
879 * Tries to break this view on the given axis. This is
880 * called by views that try to do formatting of their
881 * children. For example, a view of a paragraph will
882 * typically try to place its children into row and
883 * views representing chunks of text can sometimes be
884 * broken down into smaller pieces.
885 * <p>
886 * This is implemented to return the view itself, which
887 * represents the default behavior on not being
888 * breakable. If the view does support breaking, the
889 * starting offset of the view returned should be the
890 * given offset, and the end offset should be less than
891 * or equal to the end offset of the view being broken.
892 *
893 * @param axis may be either <code>View.X_AXIS</code> or
894 * <code>View.Y_AXIS</code>
895 * @param offset the location in the document model
896 * that a broken fragment would occupy >= 0. This
897 * would be the starting offset of the fragment
898 * returned
899 * @param pos the position along the axis that the
900 * broken view would occupy >= 0. This may be useful for
901 * things like tab calculations
902 * @param len specifies the distance along the axis
903 * where a potential break is desired >= 0
904 * @return the fragment of the view that represents the
905 * given span, if the view can be broken. If the view
906 * doesn't support breaking behavior, the view itself is
907 * returned.
908 * @see ParagraphView
909 */
910 public View breakView(int axis, int offset, float pos, float len) {
911 return this;
912 }
913
914 /**
918 * the view doesn't support fragmenting (the default), it
919 * should return itself.
920 *
921 * @param p0 the starting offset >= 0. This should be a value
922 * greater or equal to the element starting offset and
923 * less than the element ending offset.
924 * @param p1 the ending offset > p0. This should be a value
925 * less than or equal to the elements end offset and
926 * greater than the elements starting offset.
927 * @return the view fragment, or itself if the view doesn't
928 * support breaking into fragments
929 * @see LabelView
930 */
931 public View createFragment(int p0, int p1) {
932 return this;
933 }
934
935 /**
936 * Determines how attractive a break opportunity in
937 * this view is. This can be used for determining which
938 * view is the most attractive to call <code>breakView</code>
939 * on in the process of formatting. A view that represents
940 * text that has whitespace in it might be more attractive
941 * than a view that has no whitespace, for example. The
942 * higher the weight, the more attractive the break. A
943 * value equal to or lower than <code>BadBreakWeight</code>
944 * should not be considered for a break. A value greater
945 * than or equal to <code>ForcedBreakWeight</code> should
946 * be broken.
947 * <p>
948 * This is implemented to provide the default behavior
949 * of returning <code>BadBreakWeight</code> unless the length
950 * is greater than the length of the view in which case the
951 * entire view represents the fragment. Unless a view has
952 * been written to support breaking behavior, it is not
953 * attractive to try and break the view. An example of
954 * a view that does support breaking is <code>LabelView</code>.
955 * An example of a view that uses break weight is
956 * <code>ParagraphView</code>.
957 *
958 * @param axis may be either <code>View.X_AXIS</code> or
959 * <code>View.Y_AXIS</code>
960 * @param pos the potential location of the start of the
961 * broken view >= 0. This may be useful for calculating tab
962 * positions
963 * @param len specifies the relative length from <em>pos</em>
964 * where a potential break is desired >= 0
965 * @return the weight, which should be a value between
966 * ForcedBreakWeight and BadBreakWeight
967 * @see LabelView
968 * @see ParagraphView
969 * @see #BadBreakWeight
970 * @see #GoodBreakWeight
971 * @see #ExcellentBreakWeight
972 * @see #ForcedBreakWeight
973 */
974 public int getBreakWeight(int axis, float pos, float len) {
975 if (len > getPreferredSpan(axis)) {
976 return GoodBreakWeight;
977 }
978 return BadBreakWeight;
979 }
980
981 /**
982 * Determines the resizability of the view along the
983 * given axis. A value of 0 or less is not resizable.
984 *
985 * @param axis may be either <code>View.X_AXIS</code> or
986 * <code>View.Y_AXIS</code>
987 * @return the weight
988 */
989 public int getResizeWeight(int axis) {
990 return 0;
991 }
992
993 /**
994 * Sets the size of the view. This should cause
995 * layout of the view along the given axis, if it
996 * has any layout duties.
997 *
998 * @param width the width >= 0
999 * @param height the height >= 0
1000 */
1001 public void setSize(float width, float height) {
1002 }
1003
1004 /**
1005 * Fetches the container hosting the view. This is useful for
1006 * things like scheduling a repaint, finding out the host
1007 * components font, etc. The default implementation
1008 * of this is to forward the query to the parent view.
1009 *
1010 * @return the container, <code>null</code> if none
1011 */
1012 public Container getContainer() {
1013 View v = getParent();
1014 return (v != null) ? v.getContainer() : null;
1015 }
1016
1017 /**
1018 * Fetches the <code>ViewFactory</code> implementation that is feeding
1019 * the view hierarchy. Normally the views are given this
1020 * as an argument to updates from the model when they
1021 * are most likely to need the factory, but this
1022 * method serves to provide it at other times.
1023 *
1024 * @return the factory, <code>null</code> if none
1025 */
1026 public ViewFactory getViewFactory() {
1027 View v = getParent();
1028 return (v != null) ? v.getViewFactory() : null;
1029 }
1030
1031 /**
1032 * Returns the tooltip text at the specified location. The default
1033 * implementation returns the value from the child View identified by
1034 * the passed in location.
1035 * @param x the x coordinate
1036 * @param y the y coordinate
1037 * @param allocation current allocation of the View.
1038 * @return the tooltip text at the specified location
1039 *
1040 * @since 1.4
1041 * @see JTextComponent#getToolTipText
1042 */
1043 public String getToolTipText(float x, float y, Shape allocation) {
1044 int viewIndex = getViewIndex(x, y, allocation);
1045 if (viewIndex >= 0) {
1046 allocation = getChildAllocation(viewIndex, allocation);
1047 Rectangle rect = (allocation instanceof Rectangle) ?
1048 (Rectangle)allocation : allocation.getBounds();
1049 if (rect.contains(x, y)) {
1050 return getView(viewIndex).getToolTipText(x, y, allocation);
1051 }
1052 }
1053 return null;
1054 }
1055
1056 /**
1057 * Returns the child view index representing the given position in
1058 * the view. This iterates over all the children returning the
1059 * first with a bounds that contains <code>x</code>, <code>y</code>.
1060 *
1061 * @param x the x coordinate
1062 * @param y the y coordinate
1063 * @param allocation current allocation of the View.
1064 * @return index of the view representing the given location, or
1065 * -1 if no view represents that position
1066 * @since 1.4
1067 */
1068 public int getViewIndex(float x, float y, Shape allocation) {
1069 for (int counter = getViewCount() - 1; counter >= 0; counter--) {
1070 Shape childAllocation = getChildAllocation(counter, allocation);
1071
1072 if (childAllocation != null) {
1073 Rectangle rect = (childAllocation instanceof Rectangle) ?
1074 (Rectangle)childAllocation : childAllocation.getBounds();
1075
1076 if (rect.contains(x, y)) {
1077 return counter;
1078 }
1079 }
1080 }
1081 return -1;
1082 }
1083
1084 /**
1085 * Updates the child views in response to receiving notification
1086 * that the model changed, and there is change record for the
1087 * element this view is responsible for. This is implemented
1088 * to assume the child views are directly responsible for the
1089 * child elements of the element this view represents. The
1090 * <code>ViewFactory</code> is used to create child views for each element
1091 * specified as added in the <code>ElementChange</code>, starting at the
1092 * index specified in the given <code>ElementChange</code>. The number of
1093 * child views representing the removed elements specified are
1094 * removed.
1095 *
1096 * @param ec the change information for the element this view
1097 * is responsible for. This should not be <code>null</code> if
1098 * this method gets called
1099 * @param e the change information from the associated document
1100 * @param f the factory to use to build child views
1101 * @return whether or not the child views represent the
1102 * child elements of the element this view is responsible
1103 * for. Some views create children that represent a portion
1104 * of the element they are responsible for, and should return
1105 * false. This information is used to determine if views
1106 * in the range of the added elements should be forwarded to
1107 * or not
1108 * @see #insertUpdate
1109 * @see #removeUpdate
1110 * @see #changedUpdate
1111 * @since 1.3
1112 */
1113 protected boolean updateChildren(DocumentEvent.ElementChange ec,
1114 DocumentEvent e, ViewFactory f) {
1115 Element[] removedElems = ec.getChildrenRemoved();
1116 Element[] addedElems = ec.getChildrenAdded();
1117 View[] added = null;
1118 if (addedElems != null) {
1119 added = new View[addedElems.length];
1120 for (int i = 0; i < addedElems.length; i++) {
1121 added[i] = f.create(addedElems[i]);
1122 }
1123 }
1124 int nremoved = 0;
1125 int index = ec.getIndex();
1126 if (removedElems != null) {
1127 nremoved = removedElems.length;
1128 }
1129 replace(index, nremoved, added);
1130 return true;
1131 }
1132
1133 /**
1134 * Forwards the given <code>DocumentEvent</code> to the child views
1135 * that need to be notified of the change to the model.
1136 * If there were changes to the element this view is
1137 * responsible for, that should be considered when
1138 * forwarding (i.e. new child views should not get
1139 * notified).
1140 *
1141 * @param ec changes to the element this view is responsible
1142 * for (may be <code>null</code> if there were no changes).
1143 * @param e the change information from the associated document
1144 * @param a the current allocation of the view
1145 * @param f the factory to use to rebuild if the view has children
1146 * @see #insertUpdate
1147 * @see #removeUpdate
1148 * @see #changedUpdate
1149 * @since 1.3
1150 */
1151 protected void forwardUpdate(DocumentEvent.ElementChange ec,
1152 DocumentEvent e, Shape a, ViewFactory f) {
1153 calculateUpdateIndexes(e);
1154
1155 int hole0 = lastUpdateIndex + 1;
1156 int hole1 = hole0;
1157 Element[] addedElems = (ec != null) ? ec.getChildrenAdded() : null;
1158 if ((addedElems != null) && (addedElems.length > 0)) {
1159 hole0 = ec.getIndex();
1160 hole1 = hole0 + addedElems.length - 1;
1161 }
1162
1198 firstUpdateIndex = Math.max(firstUpdateIndex - 1, 0);
1199 }
1200 }
1201 if (e.getType() != DocumentEvent.EventType.REMOVE) {
1202 lastUpdateIndex = getViewIndex(pos + e.getLength(), Position.Bias.Forward);
1203 if (lastUpdateIndex < 0) {
1204 lastUpdateIndex = getViewCount() - 1;
1205 }
1206 }
1207 firstUpdateIndex = Math.max(firstUpdateIndex, 0);
1208 }
1209
1210 /**
1211 * Updates the view to reflect the changes.
1212 */
1213 void updateAfterChange() {
1214 // Do nothing by default. Should be overridden in subclasses, if any.
1215 }
1216
1217 /**
1218 * Forwards the <code>DocumentEvent</code> to the give child view. This
1219 * simply messages the view with a call to <code>insertUpdate</code>,
1220 * <code>removeUpdate</code>, or <code>changedUpdate</code> depending
1221 * upon the type of the event. This is called by
1222 * {@link #forwardUpdate forwardUpdate} to forward
1223 * the event to children that need it.
1224 *
1225 * @param v the child view to forward the event to
1226 * @param e the change information from the associated document
1227 * @param a the current allocation of the view
1228 * @param f the factory to use to rebuild if the view has children
1229 * @see #forwardUpdate
1230 * @since 1.3
1231 */
1232 protected void forwardUpdateToView(View v, DocumentEvent e,
1233 Shape a, ViewFactory f) {
1234 DocumentEvent.EventType type = e.getType();
1235 if (type == DocumentEvent.EventType.INSERT) {
1236 v.insertUpdate(e, a, f);
1237 } else if (type == DocumentEvent.EventType.REMOVE) {
1238 v.removeUpdate(e, a, f);
1239 } else {
1240 v.changedUpdate(e, a, f);
1241 }
1242 }
1243
1244 /**
1245 * Updates the layout in response to receiving notification of
1246 * change from the model. This is implemented to call
1247 * <code>preferenceChanged</code> to reschedule a new layout
1248 * if the <code>ElementChange</code> record is not <code>null</code>.
1249 *
1250 * @param ec changes to the element this view is responsible
1251 * for (may be <code>null</code> if there were no changes)
1252 * @param e the change information from the associated document
1253 * @param a the current allocation of the view
1254 * @see #insertUpdate
1255 * @see #removeUpdate
1256 * @see #changedUpdate
1257 * @since 1.3
1258 */
1259 protected void updateLayout(DocumentEvent.ElementChange ec,
1260 DocumentEvent e, Shape a) {
1261 if ((ec != null) && (a != null)) {
1262 // should damage more intelligently
1263 preferenceChanged(null, true, true);
1264 Container host = getContainer();
1265 if (host != null) {
1266 host.repaint();
1267 }
1268 }
1269 }
1270
1271 /**
1314 * @see #getBreakWeight
1315 * @see #BadBreakWeight
1316 * @see #GoodBreakWeight
1317 * @see #ExcellentBreakWeight
1318 */
1319 public static final int ForcedBreakWeight = 3000;
1320
1321 /**
1322 * Axis for format/break operations.
1323 */
1324 public static final int X_AXIS = HORIZONTAL;
1325
1326 /**
1327 * Axis for format/break operations.
1328 */
1329 public static final int Y_AXIS = VERTICAL;
1330
1331 /**
1332 * Provides a mapping from the document model coordinate space
1333 * to the coordinate space of the view mapped to it. This is
1334 * implemented to default the bias to <code>Position.Bias.Forward</code>
1335 * which was previously implied.
1336 *
1337 * @param pos the position to convert >= 0
1338 * @param a the allocated region in which to render
1339 * @return the bounding box of the given position is returned
1340 * @exception BadLocationException if the given position does
1341 * not represent a valid location in the associated document
1342 * @see View#modelToView
1343 * @deprecated
1344 */
1345 @Deprecated
1346 public Shape modelToView(int pos, Shape a) throws BadLocationException {
1347 return modelToView(pos, a, Position.Bias.Forward);
1348 }
1349
1350
1351 /**
1352 * Provides a mapping from the view coordinate space to the logical
1353 * coordinate space of the model.
1354 *
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package javax.swing.text;
26
27 import java.awt.*;
28 import javax.swing.SwingConstants;
29 import javax.swing.event.*;
30
31 /**
32 * <p>
33 * A very important part of the text package is the {@code View} class.
34 * As the name suggests it represents a view of the text model,
35 * or a piece of the text model.
36 * It is this class that is responsible for the look of the text component.
37 * The view is not intended to be some completely new thing that one must
38 * learn, but rather is much like a lightweight component.
39 * <p>
40 By default, a view is very light. It contains a reference to the parent
41 view from which it can fetch many things without holding state, and it
42 contains a reference to a portion of the model ({@code Element}).
43 A view does not
44 have to exactly represent an element in the model, that is simply a typical
45 and therefore convenient mapping. A view can alternatively maintain a couple
46 of Position objects to maintain its location in the model (i.e. represent
47 a fragment of an element). This is typically the result of formatting where
48 views have been broken down into pieces. The convenience of a substantial
49 relationship to the element makes it easier to build factories to produce the
50 views, and makes it easier to keep track of the view pieces as the model is
51 changed and the view must be changed to reflect the model. Simple views
52 therefore represent an Element directly and complex views do not.
53 <p>
54 A view has the following responsibilities:
55 <dl>
56
57 <dt><b>Participate in layout.</b>
58 <dd>
59 <p>The view has a {@code setSize} method which is like
60 {@code doLayout} and {@code setSize} in {@code Component} combined.
61 The view has a {@code preferenceChanged} method which is
62 like {@code invalidate} in {@code Component} except that one can
63 invalidate just one axis
64 and the child requesting the change is identified.
65 <p>A View expresses the size that it would like to be in terms of three
66 values, a minimum, a preferred, and a maximum span. Layout in a view is
67 can be done independently upon each axis. For a properly functioning View
68 implementation, the minimum span will be <= the preferred span which in turn
69 will be <= the maximum span.
70 </p>
71 <p style="text-align:center"><img src="doc-files/View-flexibility.jpg"
72 alt="The above text describes this graphic.">
73 <p>The minimum set of methods for layout are:
74 <ul>
75 <li>{@link #getMinimumSpan(int) getMinimumSpan}
76 <li>{@link #getPreferredSpan(int) getPreferredSpan}
77 <li>{@link #getMaximumSpan(int) getMaximumSpan}
78 <li>{@link #getAlignment(int) getAlignment}
79 <li>{@link #preferenceChanged(javax.swing.text.View, boolean, boolean) preferenceChanged}
80 <li>{@link #setSize(float, float) setSize}
81 </ul>
82
83 <p>The {@code setSize} method should be prepared to be called a number of times
84 (i.e. It may be called even if the size didn't change).
85 The {@code setSize} method
86 is generally called to make sure the View layout is complete prior to trying
87 to perform an operation on it that requires an up-to-date layout. A view's
88 size should <em>always</em> be set to a value within the minimum and maximum
89 span specified by that view. Additionally, the view must always call the
90 {@code preferenceChanged} method on the parent if it has changed the
91 values for the
92 layout it would like, and expects the parent to honor. The parent View is
93 not required to recognize a change until the {@code preferenceChanged}
94 has been sent.
95 This allows parent View implementations to cache the child requirements if
96 desired. The calling sequence looks something like the following:
97 </p>
98 <p style="text-align:center">
99 <img src="doc-files/View-layout.jpg"
100 alt="Sample calling sequence between parent view and child view:
101 setSize, getMinimum, getPreferred, getMaximum, getAlignment, setSize">
102 <p>The exact calling sequence is up to the layout functionality of
103 the parent view (if the view has any children). The view may collect
104 the preferences of the children prior to determining what it will give
105 each child, or it might iteratively update the children one at a time.
106 </p>
107
108 <dt><b>Render a portion of the model.</b>
109 <dd>
110 <p>This is done in the paint method, which is pretty much like a component
111 paint method. Views are expected to potentially populate a fairly large
112 tree. A {@code View} has the following semantics for rendering:
113 </p>
114 <ul>
115 <li>The view gets its allocation from the parent at paint time, so it
116 must be prepared to redo layout if the allocated area is different from
117 what it is prepared to deal with.
118 <li>The coordinate system is the same as the hosting {@code Component}
119 (i.e. the {@code Component} returned by the
120 {@link #getContainer getContainer} method).
121 This means a child view lives in the same coordinate system as the parent
122 view unless the parent has explicitly changed the coordinate system.
123 To schedule itself to be repainted a view can call repaint on the hosting
124 {@code Component}.
125 <li>The default is to <em>not clip</em> the children. It is more efficient
126 to allow a view to clip only if it really feels it needs clipping.
127 <li>The {@code Graphics} object given is not initialized in any way.
128 A view should set any settings needed.
129 <li>A {@code View} is inherently transparent. While a view may render into its
130 entire allocation, typically a view does not. Rendering is performed by
131 traversing down the tree of {@code View} implementations.
132 Each {@code View} is responsible
133 for rendering its children. This behavior is depended upon for thread
134 safety. While view implementations do not necessarily have to be implemented
135 with thread safety in mind, other view implementations that do make use of
136 concurrency can depend upon a tree traversal to guarantee thread safety.
137 <li>The order of views relative to the model is up to the implementation.
138 Although child views will typically be arranged in the same order that they
139 occur in the model, they may be visually arranged in an entirely different
140 order. View implementations may have Z-Order associated with them if the
141 children are overlapping.
142 </ul>
143 <p>The methods for rendering are:
144 <ul>
145 <li>{@link #paint(java.awt.Graphics, java.awt.Shape) paint}
146 </ul>
147
148 <dt><b>Translate between the model and view coordinate systems.</b>
149 <dd>
150 <p>Because the view objects are produced from a factory and therefore cannot
151 necessarily be counted upon to be in a particular pattern, one must be able
152 to perform translation to properly locate spatial representation of the model.
153 The methods for doing this are:
154 <ul>
155 <li>{@link #modelToView(int, javax.swing.text.Position.Bias, int, javax.swing.text.Position.Bias, java.awt.Shape) modelToView}
156 <li>{@link #viewToModel(float, float, java.awt.Shape, javax.swing.text.Position.Bias[]) viewToModel}
157 <li>{@link #getDocument() getDocument}
158 <li>{@link #getElement() getElement}
159 <li>{@link #getStartOffset() getStartOffset}
160 <li>{@link #getEndOffset() getEndOffset}
161 </ul>
162 <p>The layout must be valid prior to attempting to make the translation.
163 The translation is not valid, and must not be attempted while changes
164 are being broadcasted from the model via a {@code DocumentEvent}.
165 </p>
166
167 <dt><b>Respond to changes from the model.</b>
168 <dd>
169 <p>If the overall view is represented by many pieces (which is the best situation
170 if one want to be able to change the view and write the least amount of new code),
171 it would be impractical to have a huge number of {@code DocumentListener}s.
172 If each
173 view listened to the model, only a few would actually be interested in the
174 changes broadcasted at any given time. Since the model has no knowledge of
175 views, it has no way to filter the broadcast of change information. The view
176 hierarchy itself is instead responsible for propagating the change information.
177 At any level in the view hierarchy, that view knows enough about its children to
178 best distribute the change information further. Changes are therefore broadcasted
179 starting from the root of the view hierarchy.
180 The methods for doing this are:
181 <ul>
182 <li>{@link #insertUpdate insertUpdate}
183 <li>{@link #removeUpdate removeUpdate}
184 <li>{@link #changedUpdate changedUpdate}
185 </ul>
186 </dl>
187 *
188 * @author Timothy Prinzing
189 */
190 public abstract class View implements SwingConstants {
191
192 /**
193 * Creates a new {@code View} object.
194 *
195 * @param elem the {@code Element} to represent
196 */
197 public View(Element elem) {
198 this.elem = elem;
199 }
200
201 /**
202 * Returns the parent of the view.
203 *
204 * @return the parent, or {@code null} if none exists
205 */
206 public View getParent() {
207 return parent;
208 }
209
210 /**
211 * Returns a boolean that indicates whether
212 * the view is visible or not. By default
213 * all views are visible.
214 *
215 * @return always returns true
216 */
217 public boolean isVisible() {
218 return true;
219 }
220
221
222 /**
223 * Determines the preferred span for this view along an
224 * axis.
225 *
226 * @param axis may be either {@code View.X_AXIS} or
227 * {@code View.Y_AXIS}
228 * @return the span the view would like to be rendered into.
229 * Typically the view is told to render into the span
230 * that is returned, although there is no guarantee.
231 * The parent may choose to resize or break the view
232 * @see View#getPreferredSpan
233 */
234 public abstract float getPreferredSpan(int axis);
235
236 /**
237 * Determines the minimum span for this view along an
238 * axis.
239 *
240 * @param axis may be either {@code View.X_AXIS} or
241 * {@code View.Y_AXIS}
242 * @return the minimum span the view can be rendered into
243 * @see View#getPreferredSpan
244 */
245 public float getMinimumSpan(int axis) {
246 int w = getResizeWeight(axis);
247 if (w == 0) {
248 // can't resize
249 return getPreferredSpan(axis);
250 }
251 return 0;
252 }
253
254 /**
255 * Determines the maximum span for this view along an
256 * axis.
257 *
258 * @param axis may be either {@code View.X_AXIS} or
259 * {@code View.Y_AXIS}
260 * @return the maximum span the view can be rendered into
261 * @see View#getPreferredSpan
262 */
263 public float getMaximumSpan(int axis) {
264 int w = getResizeWeight(axis);
265 if (w == 0) {
266 // can't resize
267 return getPreferredSpan(axis);
268 }
269 return Integer.MAX_VALUE;
270 }
271
272 /**
273 * Child views can call this on the parent to indicate that
274 * the preference has changed and should be reconsidered
275 * for layout. By default this just propagates upward to
276 * the next parent. The root view will call
277 * {@code revalidate} on the associated text component.
278 *
279 * @param child the child view
280 * @param width true if the width preference has changed
281 * @param height true if the height preference has changed
282 * @see javax.swing.JComponent#revalidate
283 */
284 public void preferenceChanged(View child, boolean width, boolean height) {
285 View parent = getParent();
286 if (parent != null) {
287 parent.preferenceChanged(this, width, height);
288 }
289 }
290
291 /**
292 * Determines the desired alignment for this view along an
293 * axis. The desired alignment is returned. This should be
294 * a value >= 0.0 and <= 1.0, where 0 indicates alignment at
295 * the origin and 1.0 indicates alignment to the full span
296 * away from the origin. An alignment of 0.5 would be the
297 * center of the view.
298 *
299 * @param axis may be either {@code View.X_AXIS} or
300 * {@code View.Y_AXIS}
301 * @return the value 0.5
302 */
303 public float getAlignment(int axis) {
304 return 0.5f;
305 }
306
307 /**
308 * Renders using the given rendering surface and area on that
309 * surface. The view may need to do layout and create child
310 * views to enable itself to render into the given allocation.
311 *
312 * @param g the rendering surface to use
313 * @param allocation the allocated region to render into
314 */
315 public abstract void paint(Graphics g, Shape allocation);
316
317 /**
318 * Establishes the parent view for this view. This is
319 * guaranteed to be called before any other methods if the
320 * parent view is functioning properly. This is also
321 * the last method called, since it is called to indicate
322 * the view has been removed from the hierarchy as
323 * well. When this method is called to set the parent to
324 * null, this method does the same for each of its children,
325 * propagating the notification that they have been
326 * disconnected from the view tree. If this is
327 * reimplemented, {@code super.setParent()} should
328 * be called.
329 *
330 * @param parent the new parent, or {@code null} if the view is
331 * being removed from a parent
332 */
333 public void setParent(View parent) {
334 // if the parent is null then propogate down the view tree
335 if (parent == null) {
336 for (int i = 0; i < getViewCount(); i++) {
337 if (getView(i).getParent() == this) {
338 // in FlowView.java view might be referenced
339 // from two super-views as a child. see logicalView
340 getView(i).setParent(null);
341 }
342 }
343 }
344 this.parent = parent;
345 }
346
347 /**
348 * Returns the number of views in this view. Since
349 * the default is to not be a composite view this
350 * returns 0.
351 *
352 * @return the number of views >= 0
353 * @see View#getViewCount
354 */
355 public int getViewCount() {
356 return 0;
357 }
358
359 /**
360 * Gets the <i>n</i>th child view. Since there are no
361 * children by default, this returns {@code null}.
362 *
363 * @param n the number of the view to get, >= 0 && < getViewCount()
364 * @return the view
365 */
366 public View getView(int n) {
367 return null;
368 }
369
370
371 /**
372 * Removes all of the children. This is a convenience
373 * call to {@code replace}.
374 *
375 * @since 1.3
376 */
377 public void removeAll() {
378 replace(0, getViewCount(), null);
379 }
380
381 /**
382 * Removes one of the children at the given position.
383 * This is a convenience call to {@code replace}.
384 * @param i the position
385 * @since 1.3
386 */
387 public void remove(int i) {
388 replace(i, 1, null);
389 }
390
391 /**
392 * Inserts a single child view. This is a convenience
393 * call to {@code replace}.
394 *
395 * @param offs the offset of the view to insert before >= 0
396 * @param v the view
397 * @see #replace
398 * @since 1.3
399 */
400 public void insert(int offs, View v) {
401 View[] one = new View[1];
402 one[0] = v;
403 replace(offs, 0, one);
404 }
405
406 /**
407 * Appends a single child view. This is a convenience
408 * call to {@code replace}.
409 *
410 * @param v the view
411 * @see #replace
412 * @since 1.3
413 */
414 public void append(View v) {
415 View[] one = new View[1];
416 one[0] = v;
417 replace(getViewCount(), 0, one);
418 }
419
420 /**
421 * Replaces child views. If there are no views to remove
422 * this acts as an insert. If there are no views to
423 * add this acts as a remove. Views being removed will
424 * have the parent set to {@code null}, and the internal reference
425 * to them removed so that they can be garbage collected.
426 * This is implemented to do nothing, because by default
427 * a view has no children.
428 *
429 * @param offset the starting index into the child views to insert
430 * the new views. This should be a value >= 0 and <= getViewCount
431 * @param length the number of existing child views to remove
432 * This should be a value >= 0 and <= (getViewCount() - offset).
433 * @param views the child views to add. This value can be
434 * {@code null} to indicate no children are being added
435 * (useful to remove).
436 * @since 1.3
437 */
438 public void replace(int offset, int length, View[] views) {
439 }
440
441 /**
442 * Returns the child view index representing the given position in
443 * the model. By default a view has no children so this is implemented
444 * to return -1 to indicate there is no valid child index for any
445 * position.
446 *
447 * @param pos the position >= 0
448 * @param b the bias
449 * @return index of the view representing the given position, or
450 * -1 if no view represents that position
451 * @since 1.3
452 */
453 public int getViewIndex(int pos, Position.Bias b) {
454 return -1;
455 }
456
457 /**
458 * Fetches the allocation for the given child view.
459 * This enables finding out where various views
460 * are located, without assuming how the views store
461 * their location. This returns {@code null} since the
462 * default is to not have any child views.
463 *
464 * @param index the index of the child, >= 0 && <
465 * {@code getViewCount()}
466 * @param a the allocation to this view
467 * @return the allocation to the child
468 */
469 public Shape getChildAllocation(int index, Shape a) {
470 return null;
471 }
472
473 /**
474 * Provides a way to determine the next visually represented model
475 * location at which one might place a caret.
476 * Some views may not be visible,
477 * they might not be in the same order found in the model, or they just
478 * might not allow access to some of the locations in the model.
479 * This method enables specifying a position to convert
480 * within the range of >=0. If the value is -1, a position
481 * will be calculated automatically. If the value < -1,
482 * the {@code BadLocationException} will be thrown.
483 *
484 * @param pos the position to convert
485 * @param b the bias
486 * @param a the allocated region in which to render
487 * @param direction the direction from the current position that can
488 * be thought of as the arrow keys typically found on a keyboard.
489 * This will be one of the following values:
490 * <ul>
491 * <li>SwingConstants.WEST
492 * <li>SwingConstants.EAST
493 * <li>SwingConstants.NORTH
494 * <li>SwingConstants.SOUTH
495 * </ul>
496 * @param biasRet the returned bias
497 * @return the location within the model that best represents the next
498 * location visual position
499 * @exception BadLocationException the given position is not a valid
500 * position within the document
501 * @exception IllegalArgumentException if {@code direction}
502 * doesn't have one of the legal values above
503 */
504 public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a,
505 int direction, Position.Bias[] biasRet)
506 throws BadLocationException {
507 if (pos < -1 || pos > getDocument().getLength()) {
508 // -1 is a reserved value, see the code below
509 throw new BadLocationException("Invalid position", pos);
510 }
511
512 biasRet[0] = Position.Bias.Forward;
513 switch (direction) {
514 case NORTH:
515 case SOUTH:
516 {
517 if (pos == -1) {
518 pos = (direction == NORTH) ? Math.max(0, getEndOffset() - 1) :
519 getStartOffset();
520 break;
521 }
560 }
561 else {
562 pos = Math.min(pos + 1, getDocument().getLength());
563 }
564 break;
565 default:
566 throw new IllegalArgumentException("Bad direction: " + direction);
567 }
568 return pos;
569 }
570
571 /**
572 * Provides a mapping, for a given character,
573 * from the document model coordinate space
574 * to the view coordinate space.
575 *
576 * @param pos the position of the desired character (>=0)
577 * @param a the area of the view, which encompasses the requested character
578 * @param b the bias toward the previous character or the
579 * next character represented by the offset, in case the
580 * position is a boundary of two views; {@code b} will have one
581 * of these values:
582 * <ul>
583 * <li> {@code Position.Bias.Forward}
584 * <li> {@code Position.Bias.Backward}
585 * </ul>
586 * @return the bounding box, in view coordinate space,
587 * of the character at the specified position
588 * @exception BadLocationException if the specified position does
589 * not represent a valid location in the associated document
590 * @exception IllegalArgumentException if {@code b} is not one of the
591 * legal {@code Position.Bias} values listed above
592 * @see View#viewToModel
593 */
594 public abstract Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException;
595
596 /**
597 * Provides a mapping, for a given region,
598 * from the document model coordinate space
599 * to the view coordinate space. The specified region is
600 * created as a union of the first and last character positions.
601 *
602 * @param p0 the position of the first character (>=0)
603 * @param b0 the bias of the first character position,
604 * toward the previous character or the
605 * next character represented by the offset, in case the
606 * position is a boundary of two views; {@code b0} will have one
607 * of these values:
608 * <ul style="list-style-type:none">
609 * <li> {@code Position.Bias.Forward}
610 * <li> {@code Position.Bias.Backward}
611 * </ul>
612 * @param p1 the position of the last character (>=0)
613 * @param b1 the bias for the second character position, defined
614 * one of the legal values shown above
615 * @param a the area of the view, which encompasses the requested region
616 * @return the bounding box which is a union of the region specified
617 * by the first and last character positions
618 * @exception BadLocationException if the given position does
619 * not represent a valid location in the associated document
620 * @exception IllegalArgumentException if {@code b0} or
621 * {@code b1} are not one of the
622 * legal {@code Position.Bias} values listed above
623 * @see View#viewToModel
624 */
625 public Shape modelToView(int p0, Position.Bias b0, int p1, Position.Bias b1, Shape a) throws BadLocationException {
626 Shape s0 = modelToView(p0, a, b0);
627 Shape s1;
628 if (p1 == getEndOffset()) {
629 try {
630 s1 = modelToView(p1, a, b1);
631 } catch (BadLocationException ble) {
632 s1 = null;
633 }
634 if (s1 == null) {
635 // Assume extends left to right.
636 Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
637 a.getBounds();
638 s1 = new Rectangle(alloc.x + alloc.width - 1, alloc.y,
639 1, alloc.height);
640 }
641 }
642 else {
643 s1 = modelToView(p1, a, b1);
644 }
645 Rectangle r0 = s0.getBounds();
646 Rectangle r1 = (s1 instanceof Rectangle) ? (Rectangle) s1 :
647 s1.getBounds();
648 if (r0.y != r1.y) {
649 // If it spans lines, force it to be the width of the view.
650 Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
651 a.getBounds();
652 r0.x = alloc.x;
653 r0.width = alloc.width;
654 }
655 r0.add(r1);
656 return r0;
657 }
658
659 /**
660 * Provides a mapping from the view coordinate space to the logical
661 * coordinate space of the model. The {@code biasReturn}
662 * argument will be filled in to indicate that the point given is
663 * closer to the next character in the model or the previous
664 * character in the model.
665 *
666 * @param x the X coordinate >= 0
667 * @param y the Y coordinate >= 0
668 * @param a the allocated region in which to render
669 * @param biasReturn the returned bias
670 * @return the location within the model that best represents the
671 * given point in the view >= 0. The {@code biasReturn}
672 * argument will be
673 * filled in to indicate that the point given is closer to the next
674 * character in the model or the previous character in the model.
675 */
676 public abstract int viewToModel(float x, float y, Shape a, Position.Bias[] biasReturn);
677
678 /**
679 * Gives notification that something was inserted into
680 * the document in a location that this view is responsible for.
681 * To reduce the burden to subclasses, this functionality is
682 * spread out into the following calls that subclasses can
683 * reimplement:
684 * <ol>
685 * <li>{@link #updateChildren updateChildren} is called
686 * if there were any changes to the element this view is
687 * responsible for. If this view has child views that are
688 * represent the child elements, then this method should do
689 * whatever is necessary to make sure the child views correctly
690 * represent the model.
691 * <li>{@link #forwardUpdate forwardUpdate} is called
784 */
785 public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
786 if (getViewCount() > 0) {
787 Element elem = getElement();
788 DocumentEvent.ElementChange ec = e.getChange(elem);
789 if (ec != null) {
790 if (! updateChildren(ec, e, f)) {
791 // don't consider the element changes they
792 // are for a view further down.
793 ec = null;
794 }
795 }
796 forwardUpdate(ec, e, a, f);
797 updateLayout(ec, e, a);
798 }
799 }
800
801 /**
802 * Fetches the model associated with the view.
803 *
804 * @return the view model, {@code null} if none
805 * @see View#getDocument
806 */
807 public Document getDocument() {
808 return elem.getDocument();
809 }
810
811 /**
812 * Fetches the portion of the model for which this view is
813 * responsible.
814 *
815 * @return the starting offset into the model >= 0
816 * @see View#getStartOffset
817 */
818 public int getStartOffset() {
819 return elem.getStartOffset();
820 }
821
822 /**
823 * Fetches the portion of the model for which this view is
824 * responsible.
826 * @return the ending offset into the model >= 0
827 * @see View#getEndOffset
828 */
829 public int getEndOffset() {
830 return elem.getEndOffset();
831 }
832
833 /**
834 * Fetches the structural portion of the subject that this
835 * view is mapped to. The view may not be responsible for the
836 * entire portion of the element.
837 *
838 * @return the subject
839 * @see View#getElement
840 */
841 public Element getElement() {
842 return elem;
843 }
844
845 /**
846 * Fetch a {@code Graphics} for rendering.
847 * This can be used to determine
848 * font characteristics, and will be different for a print view
849 * than a component view.
850 *
851 * @return a {@code Graphics} object for rendering
852 * @since 1.3
853 */
854 public Graphics getGraphics() {
855 // PENDING(prinz) this is a temporary implementation
856 Component c = getContainer();
857 return c.getGraphics();
858 }
859
860 /**
861 * Fetches the attributes to use when rendering. By default
862 * this simply returns the attributes of the associated element.
863 * This method should be used rather than using the element
864 * directly to obtain access to the attributes to allow
865 * view-specific attributes to be mixed in or to allow the
866 * view to have view-specific conversion of attributes by
867 * subclasses.
868 * Each view should document what attributes it recognizes
869 * for the purpose of rendering or layout, and should always
870 * access them through the {@code AttributeSet} returned
871 * by this method.
872 * @return the attributes to use when rendering
873 */
874 public AttributeSet getAttributes() {
875 return elem.getAttributes();
876 }
877
878 /**
879 * Tries to break this view on the given axis. This is
880 * called by views that try to do formatting of their
881 * children. For example, a view of a paragraph will
882 * typically try to place its children into row and
883 * views representing chunks of text can sometimes be
884 * broken down into smaller pieces.
885 * <p>
886 * This is implemented to return the view itself, which
887 * represents the default behavior on not being
888 * breakable. If the view does support breaking, the
889 * starting offset of the view returned should be the
890 * given offset, and the end offset should be less than
891 * or equal to the end offset of the view being broken.
892 *
893 * @param axis may be either {@code View.X_AXIS} or
894 * {@code View.Y_AXIS}
895 * @param offset the location in the document model
896 * that a broken fragment would occupy >= 0. This
897 * would be the starting offset of the fragment
898 * returned
899 * @param pos the position along the axis that the
900 * broken view would occupy >= 0. This may be useful for
901 * things like tab calculations
902 * @param len specifies the distance along the axis
903 * where a potential break is desired >= 0
904 * @return the fragment of the view that represents the
905 * given span, if the view can be broken. If the view
906 * doesn't support breaking behavior, the view itself is
907 * returned.
908 * @see ParagraphView
909 */
910 public View breakView(int axis, int offset, float pos, float len) {
911 return this;
912 }
913
914 /**
918 * the view doesn't support fragmenting (the default), it
919 * should return itself.
920 *
921 * @param p0 the starting offset >= 0. This should be a value
922 * greater or equal to the element starting offset and
923 * less than the element ending offset.
924 * @param p1 the ending offset > p0. This should be a value
925 * less than or equal to the elements end offset and
926 * greater than the elements starting offset.
927 * @return the view fragment, or itself if the view doesn't
928 * support breaking into fragments
929 * @see LabelView
930 */
931 public View createFragment(int p0, int p1) {
932 return this;
933 }
934
935 /**
936 * Determines how attractive a break opportunity in
937 * this view is. This can be used for determining which
938 * view is the most attractive to call {@code breakView}
939 * on in the process of formatting. A view that represents
940 * text that has whitespace in it might be more attractive
941 * than a view that has no whitespace, for example. The
942 * higher the weight, the more attractive the break. A
943 * value equal to or lower than {@code BadBreakWeight}
944 * should not be considered for a break. A value greater
945 * than or equal to {@code ForcedBreakWeight} should
946 * be broken.
947 * <p>
948 * This is implemented to provide the default behavior
949 * of returning {@code BadBreakWeight} unless the length
950 * is greater than the length of the view in which case the
951 * entire view represents the fragment. Unless a view has
952 * been written to support breaking behavior, it is not
953 * attractive to try and break the view. An example of
954 * a view that does support breaking is {@code LabelView}.
955 * An example of a view that uses break weight is
956 * {@code ParagraphView}.
957 *
958 * @param axis may be either {@code View.X_AXIS} or
959 * {@code View.Y_AXIS}
960 * @param pos the potential location of the start of the
961 * broken view >= 0. This may be useful for calculating tab
962 * positions
963 * @param len specifies the relative length from <em>pos</em>
964 * where a potential break is desired >= 0
965 * @return the weight, which should be a value between
966 * ForcedBreakWeight and BadBreakWeight
967 * @see LabelView
968 * @see ParagraphView
969 * @see #BadBreakWeight
970 * @see #GoodBreakWeight
971 * @see #ExcellentBreakWeight
972 * @see #ForcedBreakWeight
973 */
974 public int getBreakWeight(int axis, float pos, float len) {
975 if (len > getPreferredSpan(axis)) {
976 return GoodBreakWeight;
977 }
978 return BadBreakWeight;
979 }
980
981 /**
982 * Determines the resizability of the view along the
983 * given axis. A value of 0 or less is not resizable.
984 *
985 * @param axis may be either {@code View.X_AXIS} or
986 * {@code View.Y_AXIS}
987 * @return the weight
988 */
989 public int getResizeWeight(int axis) {
990 return 0;
991 }
992
993 /**
994 * Sets the size of the view. This should cause
995 * layout of the view along the given axis, if it
996 * has any layout duties.
997 *
998 * @param width the width >= 0
999 * @param height the height >= 0
1000 */
1001 public void setSize(float width, float height) {
1002 }
1003
1004 /**
1005 * Fetches the container hosting the view. This is useful for
1006 * things like scheduling a repaint, finding out the host
1007 * components font, etc. The default implementation
1008 * of this is to forward the query to the parent view.
1009 *
1010 * @return the container, {@code null} if none
1011 */
1012 public Container getContainer() {
1013 View v = getParent();
1014 return (v != null) ? v.getContainer() : null;
1015 }
1016
1017 /**
1018 * Fetches the {@code ViewFactory} implementation that is feeding
1019 * the view hierarchy. Normally the views are given this
1020 * as an argument to updates from the model when they
1021 * are most likely to need the factory, but this
1022 * method serves to provide it at other times.
1023 *
1024 * @return the factory, {@code null} if none
1025 */
1026 public ViewFactory getViewFactory() {
1027 View v = getParent();
1028 return (v != null) ? v.getViewFactory() : null;
1029 }
1030
1031 /**
1032 * Returns the tooltip text at the specified location. The default
1033 * implementation returns the value from the child View identified by
1034 * the passed in location.
1035 * @param x the x coordinate
1036 * @param y the y coordinate
1037 * @param allocation current allocation of the View.
1038 * @return the tooltip text at the specified location
1039 *
1040 * @since 1.4
1041 * @see JTextComponent#getToolTipText
1042 */
1043 public String getToolTipText(float x, float y, Shape allocation) {
1044 int viewIndex = getViewIndex(x, y, allocation);
1045 if (viewIndex >= 0) {
1046 allocation = getChildAllocation(viewIndex, allocation);
1047 Rectangle rect = (allocation instanceof Rectangle) ?
1048 (Rectangle)allocation : allocation.getBounds();
1049 if (rect.contains(x, y)) {
1050 return getView(viewIndex).getToolTipText(x, y, allocation);
1051 }
1052 }
1053 return null;
1054 }
1055
1056 /**
1057 * Returns the child view index representing the given position in
1058 * the view. This iterates over all the children returning the
1059 * first with a bounds that contains {@code x}, {@code y}.
1060 *
1061 * @param x the x coordinate
1062 * @param y the y coordinate
1063 * @param allocation current allocation of the View.
1064 * @return index of the view representing the given location, or
1065 * -1 if no view represents that position
1066 * @since 1.4
1067 */
1068 public int getViewIndex(float x, float y, Shape allocation) {
1069 for (int counter = getViewCount() - 1; counter >= 0; counter--) {
1070 Shape childAllocation = getChildAllocation(counter, allocation);
1071
1072 if (childAllocation != null) {
1073 Rectangle rect = (childAllocation instanceof Rectangle) ?
1074 (Rectangle)childAllocation : childAllocation.getBounds();
1075
1076 if (rect.contains(x, y)) {
1077 return counter;
1078 }
1079 }
1080 }
1081 return -1;
1082 }
1083
1084 /**
1085 * Updates the child views in response to receiving notification
1086 * that the model changed, and there is change record for the
1087 * element this view is responsible for. This is implemented
1088 * to assume the child views are directly responsible for the
1089 * child elements of the element this view represents. The
1090 * {@code ViewFactory} is used to create child views for each element
1091 * specified as added in the {@code ElementChange}, starting at the
1092 * index specified in the given {@code ElementChange}. The number of
1093 * child views representing the removed elements specified are
1094 * removed.
1095 *
1096 * @param ec the change information for the element this view
1097 * is responsible for. This should not be {@code null} if
1098 * this method gets called
1099 * @param e the change information from the associated document
1100 * @param f the factory to use to build child views
1101 * @return whether or not the child views represent the
1102 * child elements of the element this view is responsible
1103 * for. Some views create children that represent a portion
1104 * of the element they are responsible for, and should return
1105 * false. This information is used to determine if views
1106 * in the range of the added elements should be forwarded to
1107 * or not
1108 * @see #insertUpdate
1109 * @see #removeUpdate
1110 * @see #changedUpdate
1111 * @since 1.3
1112 */
1113 protected boolean updateChildren(DocumentEvent.ElementChange ec,
1114 DocumentEvent e, ViewFactory f) {
1115 Element[] removedElems = ec.getChildrenRemoved();
1116 Element[] addedElems = ec.getChildrenAdded();
1117 View[] added = null;
1118 if (addedElems != null) {
1119 added = new View[addedElems.length];
1120 for (int i = 0; i < addedElems.length; i++) {
1121 added[i] = f.create(addedElems[i]);
1122 }
1123 }
1124 int nremoved = 0;
1125 int index = ec.getIndex();
1126 if (removedElems != null) {
1127 nremoved = removedElems.length;
1128 }
1129 replace(index, nremoved, added);
1130 return true;
1131 }
1132
1133 /**
1134 * Forwards the given {@code DocumentEvent} to the child views
1135 * that need to be notified of the change to the model.
1136 * If there were changes to the element this view is
1137 * responsible for, that should be considered when
1138 * forwarding (i.e. new child views should not get
1139 * notified).
1140 *
1141 * @param ec changes to the element this view is responsible
1142 * for (may be {@code null} if there were no changes).
1143 * @param e the change information from the associated document
1144 * @param a the current allocation of the view
1145 * @param f the factory to use to rebuild if the view has children
1146 * @see #insertUpdate
1147 * @see #removeUpdate
1148 * @see #changedUpdate
1149 * @since 1.3
1150 */
1151 protected void forwardUpdate(DocumentEvent.ElementChange ec,
1152 DocumentEvent e, Shape a, ViewFactory f) {
1153 calculateUpdateIndexes(e);
1154
1155 int hole0 = lastUpdateIndex + 1;
1156 int hole1 = hole0;
1157 Element[] addedElems = (ec != null) ? ec.getChildrenAdded() : null;
1158 if ((addedElems != null) && (addedElems.length > 0)) {
1159 hole0 = ec.getIndex();
1160 hole1 = hole0 + addedElems.length - 1;
1161 }
1162
1198 firstUpdateIndex = Math.max(firstUpdateIndex - 1, 0);
1199 }
1200 }
1201 if (e.getType() != DocumentEvent.EventType.REMOVE) {
1202 lastUpdateIndex = getViewIndex(pos + e.getLength(), Position.Bias.Forward);
1203 if (lastUpdateIndex < 0) {
1204 lastUpdateIndex = getViewCount() - 1;
1205 }
1206 }
1207 firstUpdateIndex = Math.max(firstUpdateIndex, 0);
1208 }
1209
1210 /**
1211 * Updates the view to reflect the changes.
1212 */
1213 void updateAfterChange() {
1214 // Do nothing by default. Should be overridden in subclasses, if any.
1215 }
1216
1217 /**
1218 * Forwards the {@code DocumentEvent} to the give child view. This
1219 * simply messages the view with a call to {@code insertUpdate},
1220 * {@code removeUpdate}, or {@code changedUpdate} depending
1221 * upon the type of the event. This is called by
1222 * {@link #forwardUpdate forwardUpdate} to forward
1223 * the event to children that need it.
1224 *
1225 * @param v the child view to forward the event to
1226 * @param e the change information from the associated document
1227 * @param a the current allocation of the view
1228 * @param f the factory to use to rebuild if the view has children
1229 * @see #forwardUpdate
1230 * @since 1.3
1231 */
1232 protected void forwardUpdateToView(View v, DocumentEvent e,
1233 Shape a, ViewFactory f) {
1234 DocumentEvent.EventType type = e.getType();
1235 if (type == DocumentEvent.EventType.INSERT) {
1236 v.insertUpdate(e, a, f);
1237 } else if (type == DocumentEvent.EventType.REMOVE) {
1238 v.removeUpdate(e, a, f);
1239 } else {
1240 v.changedUpdate(e, a, f);
1241 }
1242 }
1243
1244 /**
1245 * Updates the layout in response to receiving notification of
1246 * change from the model. This is implemented to call
1247 * {@code preferenceChanged} to reschedule a new layout
1248 * if the {@code ElementChange} record is not {@code null}.
1249 *
1250 * @param ec changes to the element this view is responsible
1251 * for (may be {@code null} if there were no changes)
1252 * @param e the change information from the associated document
1253 * @param a the current allocation of the view
1254 * @see #insertUpdate
1255 * @see #removeUpdate
1256 * @see #changedUpdate
1257 * @since 1.3
1258 */
1259 protected void updateLayout(DocumentEvent.ElementChange ec,
1260 DocumentEvent e, Shape a) {
1261 if ((ec != null) && (a != null)) {
1262 // should damage more intelligently
1263 preferenceChanged(null, true, true);
1264 Container host = getContainer();
1265 if (host != null) {
1266 host.repaint();
1267 }
1268 }
1269 }
1270
1271 /**
1314 * @see #getBreakWeight
1315 * @see #BadBreakWeight
1316 * @see #GoodBreakWeight
1317 * @see #ExcellentBreakWeight
1318 */
1319 public static final int ForcedBreakWeight = 3000;
1320
1321 /**
1322 * Axis for format/break operations.
1323 */
1324 public static final int X_AXIS = HORIZONTAL;
1325
1326 /**
1327 * Axis for format/break operations.
1328 */
1329 public static final int Y_AXIS = VERTICAL;
1330
1331 /**
1332 * Provides a mapping from the document model coordinate space
1333 * to the coordinate space of the view mapped to it. This is
1334 * implemented to default the bias to {@code Position.Bias.Forward}
1335 * which was previously implied.
1336 *
1337 * @param pos the position to convert >= 0
1338 * @param a the allocated region in which to render
1339 * @return the bounding box of the given position is returned
1340 * @exception BadLocationException if the given position does
1341 * not represent a valid location in the associated document
1342 * @see View#modelToView
1343 * @deprecated
1344 */
1345 @Deprecated
1346 public Shape modelToView(int pos, Shape a) throws BadLocationException {
1347 return modelToView(pos, a, Position.Bias.Forward);
1348 }
1349
1350
1351 /**
1352 * Provides a mapping from the view coordinate space to the logical
1353 * coordinate space of the model.
1354 *
|