Remove old autovect-branch by moving to "dead" directory.
[official-gcc.git] / old-autovect-branch / libjava / classpath / javax / swing / text / BoxView.java
blob5c9587dfe5d9580284d8b42d7e1a6a0c187a0fbb
1 /* BoxView.java -- An composite view
2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing.text;
41 import java.awt.Graphics;
42 import java.awt.Rectangle;
43 import java.awt.Shape;
45 import javax.swing.SizeRequirements;
47 /**
48 * An implementation of {@link CompositeView} that arranges its children in
49 * a box along one axis. This is comparable to how the <code>BoxLayout</code>
50 * works, but for <code>View</code> children.
52 * @author Roman Kennke (roman@kennke.org)
54 public class BoxView
55 extends CompositeView
58 /**
59 * The axis along which this <code>BoxView</code> is laid out.
61 int myAxis;
63 /**
64 * Indicates wether the layout in X_AXIS is valid.
66 boolean xLayoutValid;
68 /**
69 * Indicates whether the layout in Y_AXIS is valid.
71 boolean yLayoutValid;
73 /**
74 * The spans in X direction of the children.
76 int[] spansX;
78 /**
79 * The spans in Y direction of the children.
81 int[] spansY;
83 /**
84 * The offsets of the children in X direction relative to this BoxView's
85 * inner bounds.
87 int[] offsetsX;
89 /**
90 * The offsets of the children in Y direction relative to this BoxView's
91 * inner bounds.
93 int[] offsetsY;
95 /**
96 * The current width.
98 int width;
101 * The current height.
103 int height;
106 * Creates a new <code>BoxView</code> for the given
107 * <code>Element</code> and axis. Valid values for the axis are
108 * {@link View#X_AXIS} and {@link View#Y_AXIS}.
110 * @param element the element that is rendered by this BoxView
111 * @param axis the axis along which the box is laid out
113 public BoxView(Element element, int axis)
115 super(element);
116 myAxis = axis;
117 xLayoutValid = false;
118 yLayoutValid = false;
120 // Initialize the cache arrays.
121 spansX = new int[0];
122 spansY = new int[0];
123 offsetsX = new int[0];
124 offsetsY = new int[0];
126 width = 0;
127 height = 0;
131 * Returns the axis along which this <code>BoxView</code> is laid out.
133 * @return the axis along which this <code>BoxView</code> is laid out
135 public int getAxis()
137 return myAxis;
141 * Sets the axis along which this <code>BoxView</code> is laid out.
143 * Valid values for the axis are {@link View#X_AXIS} and
144 * {@link View#Y_AXIS}.
146 * @param axis the axis along which this <code>BoxView</code> is laid out
148 public void setAxis(int axis)
150 myAxis = axis;
154 * Marks the layout along the specified axis as invalid. This is triggered
155 * automatically when any of the child view changes its preferences
156 * via {@link #preferenceChanged(View, boolean, boolean)}.
158 * The layout will be updated the next time when
159 * {@link #setSize(float, float)} is called, typically from within the
160 * {@link #paint(Graphics, Shape)} method.
162 * Valid values for the axis are {@link View#X_AXIS} and
163 * {@link View#Y_AXIS}.
165 * @param axis an <code>int</code> value
167 public void layoutChanged(int axis)
169 switch (axis)
171 case X_AXIS:
172 xLayoutValid = false;
173 break;
174 case Y_AXIS:
175 yLayoutValid = false;
176 break;
177 default:
178 throw new IllegalArgumentException("Invalid axis parameter.");
183 * Returns <code>true</code> if the layout along the specified
184 * <code>axis</code> is valid, <code>false</code> otherwise.
186 * Valid values for the axis are {@link View#X_AXIS} and
187 * {@link View#Y_AXIS}.
189 * @param axis the axis
191 * @return <code>true</code> if the layout along the specified
192 * <code>axis</code> is valid, <code>false</code> otherwise
194 protected boolean isLayoutValid(int axis)
196 boolean valid = false;
197 switch (axis)
199 case X_AXIS:
200 valid = xLayoutValid;
201 break;
202 case Y_AXIS:
203 valid = yLayoutValid;
204 break;
205 default:
206 throw new IllegalArgumentException("Invalid axis parameter.");
208 return valid;
212 * Paints the child <code>View</code> at the specified <code>index</code>.
213 * This method modifies the actual values in <code>alloc</code> so make
214 * sure you have a copy of the original values if you need them.
216 * @param g the <code>Graphics</code> context to paint to
217 * @param alloc the allocated region for the child to paint into
218 * @param index the index of the child to be painted
220 * @see #childAllocation(int, Rectangle)
222 protected void paintChild(Graphics g, Rectangle alloc, int index)
224 View child = getView(index);
225 child.paint(g, alloc);
229 * Replaces child views by some other child views. If there are no views to
230 * remove (<code>length == 0</code>), the result is a simple insert, if
231 * there are no children to add (<code>view == null</code>) the result
232 * is a simple removal.
234 * In addition this invalidates the layout and resizes the internal cache
235 * for the child allocations. The old children's cached allocations can
236 * still be accessed (although they are not guaranteed to be valid), and
237 * the new children will have an initial offset and span of 0.
239 * @param offset the start offset from where to remove children
240 * @param length the number of children to remove
241 * @param views the views that replace the removed children
243 public void replace(int offset, int length, View[] views)
245 // Resize and copy data for cache arrays.
246 // The spansX cache.
247 int oldSize = getViewCount();
249 int[] newSpansX = new int[oldSize - length + views.length];
250 System.arraycopy(spansX, 0, newSpansX, 0, offset);
251 System.arraycopy(spansX, offset + length, newSpansX,
252 offset + views.length,
253 oldSize - (offset + length));
254 spansX = newSpansX;
256 // The spansY cache.
257 int[] newSpansY = new int[oldSize - length + views.length];
258 System.arraycopy(spansY, 0, newSpansY, 0, offset);
259 System.arraycopy(spansY, offset + length, newSpansY,
260 offset + views.length,
261 oldSize - (offset + length));
262 spansY = newSpansY;
264 // The offsetsX cache.
265 int[] newOffsetsX = new int[oldSize - length + views.length];
266 System.arraycopy(offsetsX, 0, newOffsetsX, 0, offset);
267 System.arraycopy(offsetsX, offset + length, newOffsetsX,
268 offset + views.length,
269 oldSize - (offset + length));
270 offsetsX = newOffsetsX;
272 // The offsetsY cache.
273 int[] newOffsetsY = new int[oldSize - length + views.length];
274 System.arraycopy(offsetsY, 0, newOffsetsY, 0, offset);
275 System.arraycopy(offsetsY, offset + length, newOffsetsY,
276 offset + views.length,
277 oldSize - (offset + length));
278 offsetsY = newOffsetsY;
280 // Actually perform the replace.
281 super.replace(offset, length, views);
283 // Invalidate layout information.
284 layoutChanged(X_AXIS);
285 layoutChanged(Y_AXIS);
289 * Renders the <code>Element</code> that is associated with this
290 * <code>View</code>.
292 * @param g the <code>Graphics</code> context to render to
293 * @param a the allocated region for the <code>Element</code>
295 public void paint(Graphics g, Shape a)
297 // Adjust size if the size is changed.
298 Rectangle bounds = a.getBounds();
300 if (bounds.width != getWidth() || bounds.height != getHeight())
301 setSize(bounds.width, bounds.height);
303 Rectangle inside = getInsideAllocation(a);
304 Rectangle copy = new Rectangle(inside);
305 int count = getViewCount();
306 for (int i = 0; i < count; ++i)
308 copy.setBounds(inside);
309 childAllocation(i, copy);
310 if (!copy.isEmpty()
311 && g.hitClip(copy.x, copy.y, copy.width, copy.height))
312 paintChild(g, copy, i);
317 * Returns the preferred span of the content managed by this
318 * <code>View</code> along the specified <code>axis</code>.
320 * @param axis the axis
322 * @return the preferred span of this <code>View</code>.
324 public float getPreferredSpan(int axis)
326 SizeRequirements sr = new SizeRequirements();
327 int pref = baselineRequirements(axis, sr).preferred;
328 return (float) pref;
331 public float getMaximumSpan(int axis)
333 if (axis == getAxis())
334 return getPreferredSpan(axis);
335 else
336 return Integer.MAX_VALUE;
340 * Calculates the size requirements for this <code>BoxView</code> along
341 * the specified axis.
343 * @param axis the axis that is examined
344 * @param sr the <code>SizeRequirements</code> object to hold the result,
345 * if <code>null</code>, a new one is created
347 * @return the size requirements for this <code>BoxView</code> along
348 * the specified axis
350 protected SizeRequirements baselineRequirements(int axis,
351 SizeRequirements sr)
353 SizeRequirements result;
354 if (axis == myAxis)
355 result = calculateMajorAxisRequirements(axis, sr);
356 else
357 result = calculateMinorAxisRequirements(axis, sr);
358 return result;
362 * Calculates the layout of the children of this <code>BoxView</code> along
363 * the specified axis.
365 * @param span the target span
366 * @param axis the axis that is examined
367 * @param offsets an empty array, filled with the offsets of the children
368 * @param spans an empty array, filled with the spans of the children
370 protected void baselineLayout(int span, int axis, int[] offsets,
371 int[] spans)
373 if (axis == myAxis)
374 layoutMajorAxis(span, axis, offsets, spans);
375 else
376 layoutMinorAxis(span, axis, offsets, spans);
380 * Calculates the size requirements of this <code>BoxView</code> along
381 * its major axis, that is the axis specified in the constructor.
383 * @param axis the axis that is examined
384 * @param sr the <code>SizeRequirements</code> object to hold the result,
385 * if <code>null</code>, a new one is created
387 * @return the size requirements for this <code>BoxView</code> along
388 * the specified axis
390 protected SizeRequirements calculateMajorAxisRequirements(int axis,
391 SizeRequirements sr)
393 SizeRequirements[] childReqs = getChildRequirements(axis);
394 return SizeRequirements.getTiledSizeRequirements(childReqs);
398 * Calculates the size requirements of this <code>BoxView</code> along
399 * its minor axis, that is the axis opposite to the axis specified in the
400 * constructor.
402 * @param axis the axis that is examined
403 * @param sr the <code>SizeRequirements</code> object to hold the result,
404 * if <code>null</code>, a new one is created
406 * @return the size requirements for this <code>BoxView</code> along
407 * the specified axis
409 protected SizeRequirements calculateMinorAxisRequirements(int axis,
410 SizeRequirements sr)
412 SizeRequirements[] childReqs = getChildRequirements(axis);
413 return SizeRequirements.getAlignedSizeRequirements(childReqs);
417 * Returns <code>true</code> if the specified point lies before the
418 * given <code>Rectangle</code>, <code>false</code> otherwise.
420 * &quot;Before&quot; is typically defined as being to the left or above.
422 * @param x the X coordinate of the point
423 * @param y the Y coordinate of the point
424 * @param r the rectangle to test the point against
426 * @return <code>true</code> if the specified point lies before the
427 * given <code>Rectangle</code>, <code>false</code> otherwise
429 protected boolean isBefore(int x, int y, Rectangle r)
431 boolean result = false;
433 if (myAxis == X_AXIS)
434 result = x < r.x;
435 else
436 result = y < r.y;
438 return result;
442 * Returns <code>true</code> if the specified point lies after the
443 * given <code>Rectangle</code>, <code>false</code> otherwise.
445 * &quot;After&quot; is typically defined as being to the right or below.
447 * @param x the X coordinate of the point
448 * @param y the Y coordinate of the point
449 * @param r the rectangle to test the point against
451 * @return <code>true</code> if the specified point lies after the
452 * given <code>Rectangle</code>, <code>false</code> otherwise
454 protected boolean isAfter(int x, int y, Rectangle r)
456 boolean result = false;
458 if (myAxis == X_AXIS)
459 result = x > r.x;
460 else
461 result = y > r.y;
463 return result;
467 * Returns the child <code>View</code> at the specified location.
469 * @param x the X coordinate
470 * @param y the Y coordinate
471 * @param r the inner allocation of this <code>BoxView</code> on entry,
472 * the allocation of the found child on exit
474 * @return the child <code>View</code> at the specified location
476 protected View getViewAtPoint(int x, int y, Rectangle r)
478 View result = null;
479 int count = getViewCount();
480 Rectangle copy = new Rectangle(r);
482 for (int i = 0; i < count; ++i)
484 copy.setBounds(r);
485 childAllocation(i, r);
486 if (copy.contains(x, y))
488 result = getView(i);
489 break;
493 if (result == null && count > 0)
494 return getView(count - 1);
495 return result;
499 * Computes the allocation for a child <code>View</code>. The parameter
500 * <code>a</code> stores the allocation of this <code>CompositeView</code>
501 * and is then adjusted to hold the allocation of the child view.
503 * @param index
504 * the index of the child <code>View</code>
505 * @param a
506 * the allocation of this <code>CompositeView</code> before the
507 * call, the allocation of the child on exit
509 protected void childAllocation(int index, Rectangle a)
511 if (! isAllocationValid())
512 layout(a.width, a.height);
514 a.x += offsetsX[index];
515 a.y += offsetsY[index];
516 a.width = spansX[index];
517 a.height = spansY[index];
521 * Lays out the children of this <code>BoxView</code> with the specified
522 * bounds.
524 * @param width the width of the allocated region for the children (that
525 * is the inner allocation of this <code>BoxView</code>
526 * @param height the height of the allocated region for the children (that
527 * is the inner allocation of this <code>BoxView</code>
529 protected void layout(int width, int height)
531 baselineLayout(width, X_AXIS, offsetsX, spansX);
532 baselineLayout(height, Y_AXIS, offsetsY, spansY);
536 * Performs the layout along the major axis of a <code>BoxView</code>.
538 * @param targetSpan the (inner) span of the <code>BoxView</code> in which
539 * to layout the children
540 * @param axis the axis along which the layout is performed
541 * @param offsets the array that holds the offsets of the children on exit
542 * @param spans the array that holds the spans of the children on exit
544 protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
545 int[] spans)
547 SizeRequirements[] childReqs = getChildRequirements(axis);
548 // Calculate the spans and offsets using the SizeRequirements uility
549 // methods.
550 SizeRequirements.calculateTiledPositions(targetSpan, null, childReqs,
551 offsets, spans);
552 validateLayout(axis);
556 * Performs the layout along the minor axis of a <code>BoxView</code>.
558 * @param targetSpan the (inner) span of the <code>BoxView</code> in which
559 * to layout the children
560 * @param axis the axis along which the layout is performed
561 * @param offsets the array that holds the offsets of the children on exit
562 * @param spans the array that holds the spans of the children on exit
564 protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
565 int[] spans)
567 SizeRequirements[] childReqs = getChildRequirements(axis);
568 // Calculate the spans and offsets using the SizeRequirements uility
569 // methods.
570 // TODO: This might be an opportunity for performance optimization. Here
571 // we could use a cached instance of SizeRequirements instead of passing
572 // null to baselineRequirements. However, this would involve rewriting
573 // the baselineRequirements() method to not use the SizeRequirements
574 // utility method, since they cannot reuse a cached instance.
575 SizeRequirements total = baselineRequirements(axis, null);
576 SizeRequirements.calculateAlignedPositions(targetSpan, total, childReqs,
577 offsets, spans);
578 validateLayout(axis);
582 * Returns <code>true</code> if the cached allocations for the children
583 * are still valid, <code>false</code> otherwise.
585 * @return <code>true</code> if the cached allocations for the children
586 * are still valid, <code>false</code> otherwise
588 protected boolean isAllocationValid()
590 return isLayoutValid(X_AXIS) && isLayoutValid(Y_AXIS);
594 * Return the current width of the box. This is the last allocated width.
596 * @return the current width of the box
598 public int getWidth()
600 return width;
604 * Return the current height of the box. This is the last allocated height.
606 * @return the current height of the box
608 public int getHeight()
610 return height;
614 * Sets the size of the view. If the actual size has changed, the layout
615 * is updated accordingly.
617 * @param width the new width
618 * @param height the new height
620 public void setSize(float width, float height)
622 if (this.width != (int) width)
623 layoutChanged(X_AXIS);
624 if (this.height != (int) height)
625 layoutChanged(Y_AXIS);
627 this.width = (int) width;
628 this.height = (int) height;
630 Rectangle outside = new Rectangle(0, 0, this.width, this.height);
631 Rectangle inside = getInsideAllocation(outside);
632 if (!isAllocationValid())
633 layout(inside.width, inside.height);
637 * Sets the layout to valid for a specific axis.
639 * @param axis the axis for which to validate the layout
641 void validateLayout(int axis)
643 if (axis == X_AXIS)
644 xLayoutValid = true;
645 if (axis == Y_AXIS)
646 yLayoutValid = true;
650 * Returns the size requirements of this view's children for the major
651 * axis.
653 * @return the size requirements of this view's children for the major
654 * axis
656 SizeRequirements[] getChildRequirements(int axis)
658 // Allocate SizeRequirements for each child view.
659 int count = getViewCount();
660 SizeRequirements[] childReqs = new SizeRequirements[count];
661 for (int i = 0; i < count; ++i)
663 View view = getView(i);
664 childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis),
665 (int) view.getPreferredSpan(axis),
666 (int) view.getMaximumSpan(axis),
667 view.getAlignment(axis));
669 return childReqs;
673 * Returns the span for the child view with the given index for the specified
674 * axis.
676 * @param axis the axis to examine, either <code>X_AXIS</code> or
677 * <code>Y_AXIS</code>
678 * @param childIndex the index of the child for for which to return the span
680 * @return the span for the child view with the given index for the specified
681 * axis
683 protected int getSpan(int axis, int childIndex)
685 if (axis == X_AXIS)
686 return spansX[childIndex];
687 else
688 return spansY[childIndex];
692 * Returns the offset for the child view with the given index for the
693 * specified axis.
695 * @param axis the axis to examine, either <code>X_AXIS</code> or
696 * <code>Y_AXIS</code>
697 * @param childIndex the index of the child for for which to return the span
699 * @return the offset for the child view with the given index for the
700 * specified axis
702 protected int getOffset(int axis, int childIndex)
704 if (axis == X_AXIS)
705 return offsetsX[childIndex];
706 else
707 return offsetsY[childIndex];
711 * Returns the alignment for this box view for the specified axis. The
712 * axis that is tiled (the major axis) will be requested to be aligned
713 * centered (0.5F). The minor axis alignment depends on the child view's
714 * total alignment.
716 * @param axis the axis which is examined
718 * @return the alignment for this box view for the specified axis
720 public float getAlignment(int axis)
722 if (axis == myAxis)
723 return 0.5F;
724 else
725 return baselineRequirements(axis, null).alignment;
729 * Called by a child View when its preferred span has changed.
731 * @param width indicates that the preferred width of the child changed.
732 * @param height indicates that the preferred height of the child changed.
733 * @param child the child View.
735 public void preferenceChanged (View child, boolean width, boolean height)
737 if (width)
738 xLayoutValid = false;
739 if (height)
740 yLayoutValid = false;
741 super.preferenceChanged(child, width, height);
745 * Maps the document model position <code>pos</code> to a Shape
746 * in the view coordinate space. This method overrides CompositeView's
747 * method to make sure the children are allocated properly before
748 * calling the super's behaviour.
750 public Shape modelToView(int pos, Shape a, Position.Bias bias)
751 throws BadLocationException
753 // Make sure everything is allocated properly and then call super
754 if (!isAllocationValid())
756 Rectangle bounds = a.getBounds();
757 setSize(bounds.width, bounds.height);
759 return super.modelToView(pos, a, bias);