/[classpath]/classpath/javax/swing/text/BoxView.java
ViewVC logotype

Diff of /classpath/javax/swing/text/BoxView.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.2.2.2 by gnu_andrew, Sun Aug 7 18:34:12 2005 UTC revision 1.2.2.3 by gnu_andrew, Sat Sep 10 15:31:54 2005 UTC
# Line 42  import java.awt.Graphics; Line 42  import java.awt.Graphics;
42  import java.awt.Rectangle;  import java.awt.Rectangle;
43  import java.awt.Shape;  import java.awt.Shape;
44    
45  // TODO: Implement this class.  import javax.swing.SizeRequirements;
46    
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.
51     *
52     * @author Roman Kennke (roman@kennke.org)
53     */
54  public class BoxView  public class BoxView
55    extends CompositeView    extends CompositeView
56  {  {
57    
58    /**    /**
59       * The axis along which this <code>BoxView</code> is laid out.
60       */
61      int myAxis;
62    
63      /**
64       * Indicates wether the layout in X_AXIS is valid.
65       */
66      boolean xLayoutValid;
67    
68      /**
69       * Indicates whether the layout in Y_AXIS is valid.
70       */
71      boolean yLayoutValid;
72    
73      /**
74       * The spans in X direction of the children.
75       */
76      int[] spansX;
77    
78      /**
79       * The spans in Y direction of the children.
80       */
81      int[] spansY;
82    
83      /**
84       * The offsets of the children in X direction relative to this BoxView's
85       * inner bounds.
86       */
87      int[] offsetsX;
88    
89      /**
90       * The offsets of the children in Y direction relative to this BoxView's
91       * inner bounds.
92       */
93      int[] offsetsY;
94    
95      /**
96       * The current width.
97       */
98      int width;
99    
100      /**
101       * The current height.
102       */
103      int height;
104    
105      /**
106     * Creates a new <code>BoxView</code> for the given     * Creates a new <code>BoxView</code> for the given
107     * <code>Element</code>.     * <code>Element</code> and axis. Valid values for the axis are
108       * {@link View#X_AXIS} and {@link View#Y_AXIS}.
109     *     *
110     * @param element the element that is rendered by this BoxView     * @param element the element that is rendered by this BoxView
111       * @param axis the axis along which the box is laid out
112     */     */
113    public BoxView(Element element)    public BoxView(Element element, int axis)
114    {    {
115      super(element);      super(element);
116        myAxis = axis;
117        xLayoutValid = false;
118        yLayoutValid = false;
119    
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];
125    
126        width = 0;
127        height = 0;
128    }    }
129    
130      /**
131       * Returns the axis along which this <code>BoxView</code> is laid out.
132       *
133       * @return the axis along which this <code>BoxView</code> is laid out
134       */
135      public int getAxis()
136      {
137        return myAxis;
138      }
139    
140      /**
141       * Sets the axis along which this <code>BoxView</code> is laid out.
142       *
143       * Valid values for the axis are {@link View#X_AXIS} and
144       * {@link View#Y_AXIS}.
145       *
146       * @param axis the axis along which this <code>BoxView</code> is laid out
147       */
148      public void setAxis(int axis)
149      {
150        myAxis = axis;
151      }
152    
153      /**
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)}.
157       *
158       * The layout will be updated the next time when {@link #setSize()} is
159       * called, typically from within the {@link #paint()} method.
160       *
161       * Valid values for the axis are {@link View#X_AXIS} and
162       * {@link View#Y_AXIS}.
163       *
164       * @param axis an <code>int</code> value
165       */
166      public void layoutChanged(int axis)
167      {
168        switch (axis)
169          {
170          case X_AXIS:
171            xLayoutValid = false;
172            break;
173          case Y_AXIS:
174            yLayoutValid = false;
175            break;
176          default:
177            throw new IllegalArgumentException("Invalid axis parameter.");
178          }
179      }
180    
181      /**
182       * Returns <code>true</code> if the layout along the specified
183       * <code>axis</code> is valid, <code>false</code> otherwise.
184       *
185       * Valid values for the axis are {@link View#X_AXIS} and
186       * {@link View#Y_AXIS}.
187       *
188       * @param axis the axis
189       *
190       * @return <code>true</code> if the layout along the specified
191       *         <code>axis</code> is valid, <code>false</code> otherwise
192       */
193      protected boolean isLayoutValid(int axis)
194      {
195        boolean valid = false;
196        switch (axis)
197          {
198          case X_AXIS:
199            valid = xLayoutValid;
200            break;
201          case Y_AXIS:
202            valid = yLayoutValid;
203            break;
204          default:
205            throw new IllegalArgumentException("Invalid axis parameter.");
206          }
207        return valid;
208      }
209    
210      /**
211       * Paints the child <code>View</code> at the specified <code>index</code>.
212       * This method modifies the actual values in <code>alloc</code> so make
213       * sure you have a copy of the original values if you need them.
214       *
215       * @param g the <code>Graphics</code> context to paint to
216       * @param alloc the allocated region for the child to paint into
217       * @param index the index of the child to be painted
218       *
219       * @see {@link #childAllocation}
220       */
221      protected void paintChild(Graphics g, Rectangle alloc, int index)
222      {
223        View child = getView(index);
224        childAllocation(index, alloc);
225        child.paint(g, alloc);
226      }
227    
228      /**
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.
233       *
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.
238       *
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
242       */
243      public void replace(int offset, int length, View[] views)
244      {
245        // Resize and copy data for cache arrays.
246        // The spansX cache.
247        int oldSize = getViewCount();
248    
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;
255    
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;
263    
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;
271    
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;
279    
280        // Actually perform the replace.
281        super.replace(offset, length, views);
282    
283        // Invalidate layout information.
284        layoutChanged(X_AXIS);
285        layoutChanged(Y_AXIS);
286      }
287    
288    /**    /**
289     * Renders the <code>Element</code> that is associated with this     * Renders the <code>Element</code> that is associated with this
# Line 68  public class BoxView Line 294  public class BoxView
294     */     */
295    public void paint(Graphics g, Shape a)    public void paint(Graphics g, Shape a)
296    {    {
297      // TODO: Implement me.      // Adjust size if the size is changed.
298    }      Rectangle bounds = a.getBounds();
299    
300        if (bounds.width != getWidth() || bounds.height != getHeight())
301          setSize(bounds.width, bounds.height);
302    
303        Rectangle inside = getInsideAllocation(a);
304    
305        Rectangle copy = new Rectangle(inside);
306        int count = getViewCount();
307        for (int i = 0; i < count; ++i)
308          {
309            // TODO: Figure out if the parameter to paintChild is meant to
310            // be the child allocation or the allocation of this BoxView.
311            // I assume the second option here.
312            // We pass this method a copy of the inside rectangle here because
313            // it modifies the actual values.
314            copy.setBounds(inside);
315            paintChild(g, copy, i);
316          }
317      }
318    
319    /**    /**
320     * Returns the preferred span of the content managed by this     * Returns the preferred span of the content managed by this
# Line 82  public class BoxView Line 326  public class BoxView
326     */     */
327    public float getPreferredSpan(int axis)    public float getPreferredSpan(int axis)
328    {    {
329      // TODO: Implement me.      SizeRequirements sr = new SizeRequirements();
330      return 0F;      int pref = baselineRequirements(axis, sr).preferred;
331        return (float) pref;
332      }
333    
334      public float getMaximumSpan(int axis)
335      {
336        if (axis == getAxis())
337          return getPreferredSpan(axis);
338        else
339          return Integer.MAX_VALUE;
340      }
341    
342      /**
343       * Calculates the size requirements for this <code>BoxView</code> along
344       * the specified axis.
345       *
346       * @param axis the axis that is examined
347       * @param sr the <code>SizeRequirements</code> object to hold the result,
348       *        if <code>null</code>, a new one is created
349       *
350       * @return the size requirements for this <code>BoxView</code> along
351       *         the specified axis
352       */
353      protected SizeRequirements baselineRequirements(int axis,
354                                                      SizeRequirements sr)
355      {
356        SizeRequirements result;
357        if (axis == myAxis)
358          result = calculateMajorAxisRequirements(axis, sr);
359        else
360          result = calculateMinorAxisRequirements(axis, sr);
361        return result;
362      }
363    
364      /**
365       * Calculates the size requirements of this <code>BoxView</code> along
366       * its major axis, that is the axis specified in the constructor.
367       *
368       * @param axis the axis that is examined
369       * @param sr the <code>SizeRequirements</code> object to hold the result,
370       *        if <code>null</code>, a new one is created
371       *
372       * @return the size requirements for this <code>BoxView</code> along
373       *         the specified axis
374       */
375      protected SizeRequirements calculateMajorAxisRequirements(int axis,
376                                                               SizeRequirements sr)
377      {
378        if (sr == null)
379          sr = new SizeRequirements();
380        else
381          {
382            sr.maximum = 0;
383            sr.minimum = 0;
384            sr.preferred = 0;
385            sr.alignment = 0.5F;
386          }
387    
388        int count = getViewCount();
389    
390        // Sum up the sizes of the children along the specified axis.
391        for (int i = 0; i < count; ++i)
392          {
393            View child = getView(i);
394            sr.minimum += child.getMinimumSpan(axis);
395            sr.preferred += child.getPreferredSpan(axis);
396            sr.maximum += child.getMaximumSpan(axis);
397          }
398        return sr;
399      }
400    
401      /**
402       * Calculates the size requirements of this <code>BoxView</code> along
403       * its minor axis, that is the axis opposite to the axis specified in the
404       * constructor.
405       *
406       * @param axis the axis that is examined
407       * @param sr the <code>SizeRequirements</code> object to hold the result,
408       *        if <code>null</code>, a new one is created
409       *
410       * @return the size requirements for this <code>BoxView</code> along
411       *         the specified axis
412       */
413      protected SizeRequirements calculateMinorAxisRequirements(int axis,
414                                                               SizeRequirements sr)
415      {
416        if (sr == null)
417          sr = new SizeRequirements();
418        else
419          {
420            sr.maximum = 0;
421            sr.minimum = 0;
422            sr.preferred = 0;
423            sr.alignment = 0.5F;
424          }
425    
426        int count = getViewCount();
427    
428        int aboveBaseline = 0;
429        int belowBaseline = 0;
430        int aboveBaselineMin = 0;
431        int belowBaselineMin = 0;
432        int aboveBaselineMax = 0;
433        int belowBaselineMax = 0;
434        
435        for (int i = 0; i < count; ++i)
436          {
437            View child = getView(i);
438            float align = child.getAlignment(axis);
439            int pref = (int) child.getPreferredSpan(axis);
440            int min = (int) child.getMinimumSpan(axis);
441            int max = (int) child.getMaximumSpan(axis);
442            aboveBaseline += (int) (align * pref);
443            belowBaseline += (int) ((1.F - align) * pref);
444            aboveBaselineMin += (int) (align * min);
445            belowBaselineMin += (int) ((1.F - align) * min);
446            aboveBaselineMax += (int) (align * max);
447            belowBaselineMax += (int) ((1.F - align) * max);
448          }
449        sr.minimum = aboveBaselineMin + belowBaselineMin;
450        sr.maximum = aboveBaselineMax + belowBaselineMax;
451        sr.preferred = aboveBaseline + belowBaseline;
452        if (aboveBaseline == 0)
453          sr.alignment = 1.0F;
454        else
455          sr.alignment = (float) (sr.preferred / aboveBaseline);
456    
457        return sr;
458    }    }
459    
460    /**    /**
# Line 101  public class BoxView Line 472  public class BoxView
472     */     */
473    protected boolean isBefore(int x, int y, Rectangle r)    protected boolean isBefore(int x, int y, Rectangle r)
474    {    {
475      // TODO: Implement this properly.      boolean result = false;
476      return false;  
477        if (myAxis == X_AXIS)
478          result = x < r.x;
479        else
480          result = y < r.y;
481    
482        return result;
483    }    }
484    
485    /**    /**
# Line 120  public class BoxView Line 497  public class BoxView
497     */     */
498    protected boolean isAfter(int x, int y, Rectangle r)    protected boolean isAfter(int x, int y, Rectangle r)
499    {    {
500      // TODO: Implement this properly.      boolean result = false;
501      return false;  
502        if (myAxis == X_AXIS)
503          result = x > r.x;
504        else
505          result = y > r.y;
506    
507        return result;
508    }    }
509    
510    /**    /**
# Line 129  public class BoxView Line 512  public class BoxView
512     *     *
513     * @param x the X coordinate     * @param x the X coordinate
514     * @param y the Y coordinate     * @param y the Y coordinate
515     * @param r the allocation of this <code>CompositeView</code>     * @param r the inner allocation of this <code>BoxView</code> on entry,
516       *        the allocation of the found child on exit
517     *     *
518     * @return the child <code>View</code> at the specified location     * @return the child <code>View</code> at the specified location
519     */     */
520    protected View getViewAtPoint(int x, int y, Rectangle r)    protected View getViewAtPoint(int x, int y, Rectangle r)
521    {    {
522      // TODO: Implement this properly.      View result = null;
523      return null;  
524        int count = getViewCount();
525        Rectangle copy = new Rectangle(r);
526    
527        for (int i = 0; i < count; ++i)
528          {
529            copy.setBounds(r);
530            childAllocation(i, r);
531            if (copy.contains(x, y))
532              {
533                result = getView(i);
534                break;
535              }
536          }
537    
538        return result;
539    }    }
540    
541    /**    /**
# Line 150  public class BoxView Line 549  public class BoxView
549     */     */
550    protected void childAllocation(int index, Rectangle a)    protected void childAllocation(int index, Rectangle a)
551    {    {
552      // TODO: Implement this properly.      if (! isAllocationValid())
553          layout(a.width, a.height);
554    
555        a.x += offsetsX[index];
556        a.y += offsetsY[index];
557        a.width = spansX[index];
558        a.height = spansY[index];
559      }
560    
561      /**
562       * Lays out the children of this <code>BoxView</code> with the specified
563       * bounds.
564       *
565       * @param width the width of the allocated region for the children (that
566       *        is the inner allocation of this <code>BoxView</code>
567       * @param height the height of the allocated region for the children (that
568       *        is the inner allocation of this <code>BoxView</code>
569       */
570      protected void layout(int width, int height)
571      {
572        this.width = width;
573        this.height = height;
574    
575        if (myAxis == X_AXIS)
576          {
577            layoutMajorAxis(width, X_AXIS, offsetsX, spansX);
578            layoutMinorAxis(height, Y_AXIS, offsetsY, spansY);
579          }
580        else
581          {
582            layoutMajorAxis(height, Y_AXIS, offsetsY, spansY);
583            layoutMinorAxis(width, X_AXIS, offsetsX, spansX);
584          }
585      }
586    
587      /**
588       * Performs the layout along the major axis of a <code>BoxView</code>.
589       *
590       * @param targetSpan the (inner) span of the <code>BoxView</code> in which
591       *        to layout the children
592       * @param axis the axis along which the layout is performed
593       * @param offsets the array that holds the offsets of the children on exit
594       * @param offsets the array that holds the spans of the children on exit
595       */
596      protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
597                                     int[] spans)
598      {
599        // Allocate SizeRequirements for each child view.
600        int count = getViewCount();
601        SizeRequirements[] childReqs = new SizeRequirements[count];
602        for (int i = 0; i < count; ++i)
603          {
604            View view = getView(i);
605            childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis),
606                                                (int) view.getPreferredSpan(axis),
607                                                (int) view.getMaximumSpan(axis),
608                                                view.getAlignment(axis));
609          }
610    
611        // Calculate the spans and offsets using the SizeRequirements uility
612        // methods.
613        SizeRequirements.calculateTiledPositions(targetSpan, null, childReqs,
614                                                 offsets, spans);
615    
616        validateLayout(axis);
617      }
618    
619      /**
620       * Performs the layout along the minor axis of a <code>BoxView</code>.
621       *
622       * @param targetSpan the (inner) span of the <code>BoxView</code> in which
623       *        to layout the children
624       * @param axis the axis along which the layout is performed
625       * @param offsets the array that holds the offsets of the children on exit
626       * @param offsets the array that holds the spans of the children on exit
627       */
628      protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
629                                     int[] spans)
630      {
631        // Allocate SizeRequirements for each child view.
632        int count = getViewCount();
633        SizeRequirements[] childReqs = new SizeRequirements[count];
634        for (int i = 0; i < count; ++i)
635          {
636            View view = getView(i);
637            childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis),
638                                                (int) view.getPreferredSpan(axis),
639                                                (int) view.getMaximumSpan(axis),
640                                                view.getAlignment(axis));
641          }
642    
643        // Calculate the spans and offsets using the SizeRequirements uility
644        // methods.
645        SizeRequirements.calculateAlignedPositions(targetSpan, null, childReqs,
646                                                   offsets, spans);
647        validateLayout(axis);
648      }
649    
650      /**
651       * Returns <code>true</code> if the cached allocations for the children
652       * are still valid, <code>false</code> otherwise.
653       *
654       * @return <code>true</code> if the cached allocations for the children
655       *         are still valid, <code>false</code> otherwise
656       */
657      protected boolean isAllocationValid()
658      {
659        return isLayoutValid(X_AXIS) && isLayoutValid(Y_AXIS);
660      }
661    
662      /**
663       * Return the current width of the box. This is the last allocated width.
664       *
665       * @return the current width of the box
666       */
667      public int getWidth()
668      {
669        return width;
670      }
671    
672      /**
673       * Return the current height of the box. This is the last allocated height.
674       *
675       * @return the current height of the box
676       */
677      public int getHeight()
678      {
679        return height;
680      }
681    
682      /**
683       * Sets the size of the view. If the actual size has changed, the layout
684       * is updated accordingly.
685       *
686       * @param width the new width
687       * @param height the new height
688       */
689      public void setSize(float width, float height)
690      {
691        if (this.width != (int) width)
692          layoutChanged(X_AXIS);
693        if (this.height != (int) height)
694          layoutChanged(Y_AXIS);
695    
696        Rectangle outside = new Rectangle(0, 0, this.width, this.height);
697        Rectangle inside = getInsideAllocation(outside);
698        if (!isAllocationValid())
699          layout(inside.width, inside.height);
700      }
701    
702      /**
703       * Sets the layout to valid for a specific axis.
704       *
705       * @param axis the axis for which to validate the layout
706       */
707      void validateLayout(int axis)
708      {
709        if (axis == X_AXIS)
710          xLayoutValid = true;
711        if (axis == Y_AXIS)
712          yLayoutValid = true;
713    }    }
714  }  }

Legend:
Removed from v.1.2.2.2  
changed lines
  Added in v.1.2.2.3

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26