OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [javax/] [swing/] [text/] [BoxView.java] - Blame information for rev 772

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 772 jeremybenn
/* BoxView.java -- An composite view
2
   Copyright (C) 2005, 2006  Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
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.
10
 
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.
15
 
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.
20
 
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.
25
 
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. */
37
 
38
 
39
package javax.swing.text;
40
 
41
import java.awt.Container;
42
import java.awt.Graphics;
43
import java.awt.Rectangle;
44
import java.awt.Shape;
45
 
46
import javax.swing.SizeRequirements;
47
import javax.swing.event.DocumentEvent;
48
 
49
/**
50
 * An implementation of {@link CompositeView} that arranges its children in
51
 * a box along one axis. This is comparable to how the <code>BoxLayout</code>
52
 * works, but for <code>View</code> children.
53
 *
54
 * @author Roman Kennke (roman@kennke.org)
55
 */
56
public class BoxView
57
  extends CompositeView
58
{
59
 
60
  /**
61
   * The axis along which this <code>BoxView</code> is laid out.
62
   */
63
  private int myAxis;
64
 
65
  /**
66
   * Indicates if the layout is valid along X_AXIS or Y_AXIS.
67
   */
68
  private boolean[] layoutValid = new boolean[2];
69
 
70
  /**
71
   * Indicates if the requirements for an axis are valid.
72
   */
73
  private boolean[] requirementsValid = new boolean[2];
74
 
75
  /**
76
   * The spans along the X_AXIS and Y_AXIS.
77
   */
78
  private int[][] spans = new int[2][];
79
 
80
  /**
81
   * The offsets of the children along the X_AXIS and Y_AXIS.
82
   */
83
  private int[][] offsets = new int[2][];
84
 
85
  /**
86
   * The size requirements along the X_AXIS and Y_AXIS.
87
   */
88
  private SizeRequirements[] requirements = new SizeRequirements[2];
89
 
90
  /**
91
   * The current span along X_AXIS or Y_AXIS.
92
   */
93
  private int[] span = new int[2];
94
 
95
  /**
96
   * Creates a new <code>BoxView</code> for the given
97
   * <code>Element</code> and axis. Valid values for the axis are
98
   * {@link View#X_AXIS} and {@link View#Y_AXIS}.
99
   *
100
   * @param element the element that is rendered by this BoxView
101
   * @param axis the axis along which the box is laid out
102
   */
103
  public BoxView(Element element, int axis)
104
  {
105
    super(element);
106
    myAxis = axis;
107
    layoutValid[0] = false;
108
    layoutValid[1] = false;
109
    requirementsValid[X_AXIS] = false;
110
    requirementsValid[Y_AXIS] = false;
111
    span[0] = 0;
112
    span[1] = 0;
113
    requirements[0] = new SizeRequirements();
114
    requirements[1] = new SizeRequirements();
115
 
116
    // Initialize the cache arrays.
117
    spans[0] = new int[0];
118
    spans[1] = new int[0];
119
    offsets[0] = new int[0];
120
    offsets[1] = new int[0];
121
  }
122
 
123
  /**
124
   * Returns the axis along which this <code>BoxView</code> is laid out.
125
   *
126
   * @return the axis along which this <code>BoxView</code> is laid out
127
   *
128
   * @since 1.3
129
   */
130
  public int getAxis()
131
  {
132
    return myAxis;
133
  }
134
 
135
  /**
136
   * Sets the axis along which this <code>BoxView</code> is laid out.
137
   *
138
   * Valid values for the axis are {@link View#X_AXIS} and
139
   * {@link View#Y_AXIS}.
140
   *
141
   * @param axis the axis along which this <code>BoxView</code> is laid out
142
   *
143
   * @since 1.3
144
   */
145
  public void setAxis(int axis)
146
  {
147
    boolean changed = axis != myAxis;
148
    myAxis = axis;
149
    if (changed)
150
      preferenceChanged(null, true, true);
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
159
   * {@link #setSize(float, float)} is called, typically from within the
160
   * {@link #paint(Graphics, Shape)} method.
161
   *
162
   * Valid values for the axis are {@link View#X_AXIS} and
163
   * {@link View#Y_AXIS}.
164
   *
165
   * @param axis an <code>int</code> value
166
   *
167
   * @since 1.3
168
   */
169
  public void layoutChanged(int axis)
170
  {
171
    if (axis != X_AXIS && axis != Y_AXIS)
172
      throw new IllegalArgumentException("Invalid axis parameter.");
173
    layoutValid[axis] = false;
174
  }
175
 
176
  /**
177
   * Returns <code>true</code> if the layout along the specified
178
   * <code>axis</code> is valid, <code>false</code> otherwise.
179
   *
180
   * Valid values for the axis are {@link View#X_AXIS} and
181
   * {@link View#Y_AXIS}.
182
   *
183
   * @param axis the axis
184
   *
185
   * @return <code>true</code> if the layout along the specified
186
   *         <code>axis</code> is valid, <code>false</code> otherwise
187
   *
188
   * @since 1.4
189
   */
190
  protected boolean isLayoutValid(int axis)
191
  {
192
    if (axis != X_AXIS && axis != Y_AXIS)
193
      throw new IllegalArgumentException("Invalid axis parameter.");
194
    return layoutValid[axis];
195
  }
196
 
197
  /**
198
   * Paints the child <code>View</code> at the specified <code>index</code>.
199
   * This method modifies the actual values in <code>alloc</code> so make
200
   * sure you have a copy of the original values if you need them.
201
   *
202
   * @param g the <code>Graphics</code> context to paint to
203
   * @param alloc the allocated region for the child to paint into
204
   * @param index the index of the child to be painted
205
   *
206
   * @see #childAllocation(int, Rectangle)
207
   */
208
  protected void paintChild(Graphics g, Rectangle alloc, int index)
209
  {
210
    View child = getView(index);
211
    child.paint(g, alloc);
212
  }
213
 
214
  /**
215
   * Replaces child views by some other child views. If there are no views to
216
   * remove (<code>length == 0</code>), the result is a simple insert, if
217
   * there are no children to add (<code>view == null</code>) the result
218
   * is a simple removal.
219
   *
220
   * In addition this invalidates the layout and resizes the internal cache
221
   * for the child allocations. The old children's cached allocations can
222
   * still be accessed (although they are not guaranteed to be valid), and
223
   * the new children will have an initial offset and span of 0.
224
   *
225
   * @param offset the start offset from where to remove children
226
   * @param length the number of children to remove
227
   * @param views the views that replace the removed children
228
   */
229
  public void replace(int offset, int length, View[] views)
230
  {
231
    // Actually perform the replace.
232
    super.replace(offset, length, views);
233
 
234
    // Resize and copy data for cache arrays.
235
    int newItems = views != null ? views.length : 0;
236
    int minor = 1 - myAxis;
237
    offsets[myAxis] = replaceLayoutArray(offsets[myAxis], offset, newItems);
238
    spans[myAxis] = replaceLayoutArray(spans[myAxis], offset, newItems);
239
    layoutValid[myAxis] = false;
240
    requirementsValid[myAxis] = false;
241
    offsets[minor] = replaceLayoutArray(offsets[minor], offset, newItems);
242
    spans[minor] = replaceLayoutArray(spans[minor], offset, newItems);
243
    layoutValid[minor] = false;
244
    requirementsValid[minor] = false;
245
  }
246
 
247
  /**
248
   * Helper method. This updates the layout cache arrays in response
249
   * to a call to {@link #replace(int, int, View[])}.
250
   *
251
   * @param oldArray the old array
252
   *
253
   * @return the replaced array
254
   */
255
  private int[] replaceLayoutArray(int[] oldArray, int offset, int newItems)
256
 
257
  {
258
    int num = getViewCount();
259
    int[] newArray = new int[num];
260
    System.arraycopy(oldArray, 0, newArray, 0, offset);
261
    System.arraycopy(oldArray, offset, newArray, offset + newItems,
262
                     num - newItems - offset);
263
    return newArray;
264
  }
265
 
266
  /**
267
   * A Rectangle instance to be reused in the paint() method below.
268
   */
269
  private final Rectangle tmpRect = new Rectangle();
270
 
271
  private Rectangle clipRect = new Rectangle();
272
 
273
  /**
274
   * Renders the <code>Element</code> that is associated with this
275
   * <code>View</code>.
276
   *
277
   * @param g the <code>Graphics</code> context to render to
278
   * @param a the allocated region for the <code>Element</code>
279
   */
280
  public void paint(Graphics g, Shape a)
281
  {
282
    // Try to avoid allocation if possible (almost all cases).
283
    Rectangle alloc = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
284
 
285
    // This returns a cached instance.
286
    alloc = getInsideAllocation(alloc);
287
 
288
    int count = getViewCount();
289
    for (int i = 0; i < count; i++)
290
      {
291
        View child = getView(i);
292
        tmpRect.setBounds(alloc);
293
        childAllocation(i, tmpRect);
294
        if (g.hitClip(tmpRect.x, tmpRect.y, tmpRect.width, tmpRect.height))
295
          paintChild(g, tmpRect, i);
296
      }
297
  }
298
 
299
  /**
300
   * Returns the preferred span of the content managed by this
301
   * <code>View</code> along the specified <code>axis</code>.
302
   *
303
   * @param axis the axis
304
   *
305
   * @return the preferred span of this <code>View</code>.
306
   */
307
  public float getPreferredSpan(int axis)
308
  {
309
    updateRequirements(axis);
310
    // Add margin.
311
    float margin;
312
    if (axis == X_AXIS)
313
      margin = getLeftInset() + getRightInset();
314
    else
315
      margin = getTopInset() + getBottomInset();
316
    return requirements[axis].preferred + margin;
317
  }
318
 
319
  /**
320
   * Returns the maximum span of this view along the specified axis.
321
   * This returns <code>Integer.MAX_VALUE</code> for the minor axis
322
   * and the preferred span for the major axis.
323
   *
324
   * @param axis the axis
325
   *
326
   * @return the maximum span of this view along the specified axis
327
   */
328
  public float getMaximumSpan(int axis)
329
  {
330
    updateRequirements(axis);
331
    // Add margin.
332
    float margin;
333
    if (axis == X_AXIS)
334
      margin = getLeftInset() + getRightInset();
335
    else
336
      margin = getTopInset() + getBottomInset();
337
    return requirements[axis].maximum + margin;
338
  }
339
 
340
  /**
341
   * Returns the minimum span of this view along the specified axis.
342
   * This calculates the minimum span using
343
   * {@link #calculateMajorAxisRequirements} or
344
   * {@link #calculateMinorAxisRequirements} (depending on the axis) and
345
   * returns the resulting minimum span.
346
   *
347
   * @param axis the axis
348
   *
349
   * @return the minimum span of this view along the specified axis
350
   */
351
  public float getMinimumSpan(int axis)
352
  {
353
    updateRequirements(axis);
354
    // Add margin.
355
    float margin;
356
    if (axis == X_AXIS)
357
      margin = getLeftInset() + getRightInset();
358
    else
359
      margin = getTopInset() + getBottomInset();
360
    return requirements[axis].minimum + margin;
361
  }
362
 
363
  /**
364
   * Calculates size requirements for a baseline layout. This is not
365
   * used by the BoxView itself, but by subclasses that wish to perform
366
   * a baseline layout, like the FlowView's rows.
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 baselineRequirements(int axis,
376
                                                  SizeRequirements sr)
377
  {
378
    // Create new instance if sr == null.
379
    if (sr == null)
380
      sr = new SizeRequirements();
381
    sr.alignment = 0.5F;
382
 
383
    // Calculate overall ascent and descent.
384
    int totalAscentMin = 0;
385
    int totalAscentPref = 0;
386
    int totalAscentMax = 0;
387
    int totalDescentMin = 0;
388
    int totalDescentPref = 0;
389
    int totalDescentMax = 0;
390
 
391
    int count = getViewCount();
392
    for (int i = 0; i < count; i++)
393
      {
394
        View v = getView(i);
395
        float align = v.getAlignment(axis);
396
        int span = (int) v.getPreferredSpan(axis);
397
        int ascent = (int) (align * span);
398
        int descent = span - ascent;
399
 
400
        totalAscentPref = Math.max(ascent, totalAscentPref);
401
        totalDescentPref = Math.max(descent, totalDescentPref);
402
        if (v.getResizeWeight(axis) > 0)
403
          {
404
            // If the view is resizable, then use the min and max size
405
            // of the view.
406
            span = (int) v.getMinimumSpan(axis);
407
            ascent = (int) (align * span);
408
            descent = span - ascent;
409
            totalAscentMin = Math.max(ascent, totalAscentMin);
410
            totalDescentMin = Math.max(descent, totalDescentMin);
411
 
412
            span = (int) v.getMaximumSpan(axis);
413
            ascent = (int) (align * span);
414
            descent = span - ascent;
415
            totalAscentMax = Math.max(ascent, totalAscentMax);
416
            totalDescentMax = Math.max(descent, totalDescentMax);
417
          }
418
        else
419
          {
420
            // If the view is not resizable, use the preferred span.
421
            totalAscentMin = Math.max(ascent, totalAscentMin);
422
            totalDescentMin = Math.max(descent, totalDescentMin);
423
            totalAscentMax = Math.max(ascent, totalAscentMax);
424
            totalDescentMax = Math.max(descent, totalDescentMax);
425
          }
426
      }
427
 
428
    // Preferred overall span is the sum of the preferred ascent and descent.
429
    // With overflow check.
430
    sr.preferred = (int) Math.min((long) totalAscentPref
431
                                  + (long) totalDescentPref,
432
                                  Integer.MAX_VALUE);
433
 
434
    // Align along the baseline.
435
    if (sr.preferred > 0)
436
      sr.alignment = (float) totalAscentPref / sr.preferred;
437
 
438
    if (sr.alignment == 0)
439
      {
440
        // Nothing above the baseline, use the descent.
441
        sr.minimum = totalDescentMin;
442
        sr.maximum = totalDescentMax;
443
      }
444
    else if (sr.alignment == 1.0F)
445
      {
446
        // Nothing below the baseline, use the descent.
447
        sr.minimum = totalAscentMin;
448
        sr.maximum = totalAscentMax;
449
      }
450
    else
451
      {
452
        sr.minimum = Math.max((int) (totalAscentMin / sr.alignment),
453
                              (int) (totalDescentMin / (1.0F - sr.alignment)));
454
        sr.maximum = Math.min((int) (totalAscentMax / sr.alignment),
455
                              (int) (totalDescentMax / (1.0F - sr.alignment)));
456
      }
457
    return sr;
458
  }
459
 
460
  /**
461
   * Calculates the baseline layout of the children of this
462
   * <code>BoxView</code> along the specified axis.
463
   *
464
   * This is not used by the BoxView itself, but by subclasses that wish to
465
   * perform a baseline layout, like the FlowView's rows.
466
   *
467
   * @param span the target span
468
   * @param axis the axis that is examined
469
   * @param offsets an empty array, filled with the offsets of the children
470
   * @param spans an empty array, filled with the spans of the children
471
   */
472
  protected void baselineLayout(int span, int axis, int[] offsets,
473
                                int[] spans)
474
  {
475
    int totalAscent = (int) (span * getAlignment(axis));
476
    int totalDescent = span - totalAscent;
477
 
478
    int count = getViewCount();
479
    for (int i = 0; i < count; i++)
480
      {
481
        View v = getView(i);
482
        float align = v.getAlignment(axis);
483
        int viewSpan;
484
        if (v.getResizeWeight(axis) > 0)
485
          {
486
            // If possible, then resize for best fit.
487
            int min = (int) v.getMinimumSpan(axis);
488
            int max = (int) v.getMaximumSpan(axis);
489
            if (align == 0.0F)
490
              viewSpan = Math.max(Math.min(max, totalDescent), min);
491
            else if (align == 1.0F)
492
              viewSpan = Math.max(Math.min(max, totalAscent), min);
493
            else
494
              {
495
                int fit = (int) Math.min(totalAscent / align,
496
                                         totalDescent / (1.0F - align));
497
                viewSpan = Math.max(Math.min(max, fit), min);
498
              }
499
          }
500
        else
501
          viewSpan = (int) v.getPreferredSpan(axis);
502
        offsets[i] = totalAscent - (int) (viewSpan * align);
503
        spans[i] = viewSpan;
504
      }
505
  }
506
 
507
  /**
508
   * Calculates the size requirements of this <code>BoxView</code> along
509
   * its major axis, that is the axis specified in the constructor.
510
   *
511
   * @param axis the axis that is examined
512
   * @param sr the <code>SizeRequirements</code> object to hold the result,
513
   *        if <code>null</code>, a new one is created
514
   *
515
   * @return the size requirements for this <code>BoxView</code> along
516
   *         the specified axis
517
   */
518
  protected SizeRequirements calculateMajorAxisRequirements(int axis,
519
                                                           SizeRequirements sr)
520
  {
521
    SizeRequirements res = sr;
522
    if (res == null)
523
      res = new SizeRequirements();
524
 
525
    float min = 0;
526
    float pref = 0;
527
    float max = 0;
528
 
529
    int n = getViewCount();
530
    for (int i = 0; i < n; i++)
531
      {
532
        View child = getView(i);
533
        min += child.getMinimumSpan(axis);
534
        pref += child.getPreferredSpan(axis);
535
        max += child.getMaximumSpan(axis);
536
      }
537
 
538
    res.minimum = (int) min;
539
    res.preferred = (int) pref;
540
    res.maximum = (int) max;
541
    res.alignment = 0.5F;
542
 
543
    return res;
544
  }
545
 
546
  /**
547
   * Calculates the size requirements of this <code>BoxView</code> along
548
   * its minor axis, that is the axis opposite to the axis specified in the
549
   * constructor.
550
   *
551
   * @param axis the axis that is examined
552
   * @param sr the <code>SizeRequirements</code> object to hold the result,
553
   *        if <code>null</code>, a new one is created
554
   *
555
   * @return the size requirements for this <code>BoxView</code> along
556
   *         the specified axis
557
   */
558
  protected SizeRequirements calculateMinorAxisRequirements(int axis,
559
                                                            SizeRequirements sr)
560
  {
561
    SizeRequirements res = sr;
562
    if (res == null)
563
      res = new SizeRequirements();
564
 
565
    res.minimum = 0;
566
    res.preferred = 0;
567
    res.maximum = Integer.MAX_VALUE;
568
    res.alignment = 0.5F;
569
    int n = getViewCount();
570
    for (int i = 0; i < n; i++)
571
      {
572
        View child = getView(i);
573
        res.minimum = Math.max((int) child.getMinimumSpan(axis), res.minimum);
574
        res.preferred = Math.max((int) child.getPreferredSpan(axis),
575
                                 res.preferred);
576
        res.maximum = Math.max((int) child.getMaximumSpan(axis), res.maximum);
577
      }
578
 
579
    return res;
580
  }
581
 
582
 
583
  /**
584
   * Returns <code>true</code> if the specified point lies before the
585
   * given <code>Rectangle</code>, <code>false</code> otherwise.
586
   *
587
   * &quot;Before&quot; is typically defined as being to the left or above.
588
   *
589
   * @param x the X coordinate of the point
590
   * @param y the Y coordinate of the point
591
   * @param r the rectangle to test the point against
592
   *
593
   * @return <code>true</code> if the specified point lies before the
594
   *         given <code>Rectangle</code>, <code>false</code> otherwise
595
   */
596
  protected boolean isBefore(int x, int y, Rectangle r)
597
  {
598
    boolean result = false;
599
 
600
    if (myAxis == X_AXIS)
601
      result = x < r.x;
602
    else
603
      result = y < r.y;
604
 
605
    return result;
606
  }
607
 
608
  /**
609
   * Returns <code>true</code> if the specified point lies after the
610
   * given <code>Rectangle</code>, <code>false</code> otherwise.
611
   *
612
   * &quot;After&quot; is typically defined as being to the right or below.
613
   *
614
   * @param x the X coordinate of the point
615
   * @param y the Y coordinate of the point
616
   * @param r the rectangle to test the point against
617
   *
618
   * @return <code>true</code> if the specified point lies after the
619
   *         given <code>Rectangle</code>, <code>false</code> otherwise
620
   */
621
  protected boolean isAfter(int x, int y, Rectangle r)
622
  {
623
    boolean result = false;
624
 
625
    if (myAxis == X_AXIS)
626
      result = x > r.x + r.width;
627
    else
628
      result = y > r.y + r.height;
629
 
630
    return result;
631
  }
632
 
633
  /**
634
   * Returns the child <code>View</code> at the specified location.
635
   *
636
   * @param x the X coordinate
637
   * @param y the Y coordinate
638
   * @param r the inner allocation of this <code>BoxView</code> on entry,
639
   *        the allocation of the found child on exit
640
   *
641
   * @return the child <code>View</code> at the specified location
642
   */
643
  protected View getViewAtPoint(int x, int y, Rectangle r)
644
  {
645
    View result = null;
646
    int count = getViewCount();
647
    if (myAxis == X_AXIS)
648
      {
649
        // Border case. Requested point is left from the box.
650
        if (x < r.x + offsets[X_AXIS][0])
651
          {
652
            childAllocation(0, r);
653
            result = getView(0);
654
          }
655
        else
656
          {
657
            // Search views inside box.
658
            for (int i = 0; i < count && result == null; i++)
659
              {
660
                if (x < r.x + offsets[X_AXIS][i])
661
                  {
662
                    childAllocation(i - 1, r);
663
                    result = getView(i - 1);
664
                  }
665
              }
666
          }
667
      }
668
    else // Same algorithm for Y_AXIS.
669
      {
670
        // Border case. Requested point is above the box.
671
        if (y < r.y + offsets[Y_AXIS][0])
672
          {
673
            childAllocation(0, r);
674
            result = getView(0);
675
          }
676
        else
677
          {
678
            // Search views inside box.
679
            for (int i = 0; i < count && result == null; i++)
680
              {
681
                if (y < r.y + offsets[Y_AXIS][i])
682
                  {
683
                    childAllocation(i - 1, r);
684
                    result = getView(i - 1);
685
                  }
686
              }
687
          }
688
      }
689
    // Not found, other border case: point is right from or below the box.
690
    if (result == null)
691
      {
692
        childAllocation(count - 1, r);
693
        result = getView(count - 1);
694
      }
695
    return result;
696
  }
697
 
698
  /**
699
   * Computes the allocation for a child <code>View</code>. The parameter
700
   * <code>a</code> stores the allocation of this <code>CompositeView</code>
701
   * and is then adjusted to hold the allocation of the child view.
702
   *
703
   * @param index
704
   *          the index of the child <code>View</code>
705
   * @param a
706
   *          the allocation of this <code>CompositeView</code> before the
707
   *          call, the allocation of the child on exit
708
   */
709
  protected void childAllocation(int index, Rectangle a)
710
  {
711
    a.x += offsets[X_AXIS][index];
712
    a.y += offsets[Y_AXIS][index];
713
    a.width = spans[X_AXIS][index];
714
    a.height = spans[Y_AXIS][index];
715
  }
716
 
717
  /**
718
   * Lays out the children of this <code>BoxView</code> with the specified
719
   * bounds.
720
   *
721
   * @param width the width of the allocated region for the children (that
722
   *        is the inner allocation of this <code>BoxView</code>
723
   * @param height the height of the allocated region for the children (that
724
   *        is the inner allocation of this <code>BoxView</code>
725
   */
726
  protected void layout(int width, int height)
727
  {
728
    layoutAxis(X_AXIS, width);
729
    layoutAxis(Y_AXIS, height);
730
  }
731
 
732
  private void layoutAxis(int axis, int s)
733
  {
734
    if (span[axis] != s)
735
      layoutValid[axis] = false;
736
    if (! layoutValid[axis])
737
      {
738
        span[axis] = s;
739
        updateRequirements(axis);
740
        if (axis == myAxis)
741
          layoutMajorAxis(span[axis], axis, offsets[axis], spans[axis]);
742
        else
743
          layoutMinorAxis(span[axis], axis, offsets[axis], spans[axis]);
744
        layoutValid[axis] = true;
745
 
746
        // Push out child layout.
747
        int viewCount = getViewCount();
748
        for (int i = 0; i < viewCount; i++)
749
          {
750
            View v = getView(i);
751
            v.setSize(spans[X_AXIS][i], spans[Y_AXIS][i]);
752
          }
753
      }
754
  }
755
 
756
  /**
757
   * Performs the layout along the major axis of a <code>BoxView</code>.
758
   *
759
   * @param targetSpan the (inner) span of the <code>BoxView</code> in which
760
   *        to layout the children
761
   * @param axis the axis along which the layout is performed
762
   * @param offsets the array that holds the offsets of the children on exit
763
   * @param spans the array that holds the spans of the children on exit
764
   */
765
  protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
766
                                 int[] spans)
767
  {
768
    // Set the spans to the preferred sizes. Determine the space
769
    // that we have to adjust the sizes afterwards.
770
    long sumPref = 0;
771
    int n = getViewCount();
772
    for (int i = 0; i < n; i++)
773
      {
774
        View child = getView(i);
775
        spans[i] = (int) child.getPreferredSpan(axis);
776
        sumPref += spans[i];
777
      }
778
 
779
    // Try to adjust the spans so that we fill the targetSpan.
780
    long diff = targetSpan - sumPref;
781
    float factor = 0.0F;
782
    int[] diffs = null;
783
    if (diff != 0)
784
      {
785
        long total = 0;
786
        diffs = new int[n];
787
        for (int i = 0; i < n; i++)
788
          {
789
            View child = getView(i);
790
            int span;
791
            if (diff < 0)
792
              {
793
                span = (int) child.getMinimumSpan(axis);
794
                diffs[i] = spans[i] - span;
795
              }
796
            else
797
              {
798
                span = (int) child.getMaximumSpan(axis);
799
                diffs[i] = span - spans[i];
800
              }
801
            total += span;
802
          }
803
 
804
        float maxAdjust = Math.abs(total - sumPref);
805
        factor = diff / maxAdjust;
806
        factor = Math.min(factor, 1.0F);
807
        factor = Math.max(factor, -1.0F);
808
      }
809
 
810
    // Actually perform adjustments.
811
    int totalOffs = 0;
812
    for (int i = 0; i < n; i++)
813
      {
814
        offsets[i] = totalOffs;
815
        if (diff != 0)
816
          {
817
            float adjust = factor * diffs[i];
818
            spans[i] += Math.round(adjust);
819
          }
820
        // Avoid overflow here.
821
        totalOffs = (int) Math.min((long) totalOffs + (long) spans[i],
822
                                    Integer.MAX_VALUE);
823
      }
824
  }
825
 
826
  /**
827
   * Performs the layout along the minor axis of a <code>BoxView</code>.
828
   *
829
   * @param targetSpan the (inner) span of the <code>BoxView</code> in which
830
   *        to layout the children
831
   * @param axis the axis along which the layout is performed
832
   * @param offsets the array that holds the offsets of the children on exit
833
   * @param spans the array that holds the spans of the children on exit
834
   */
835
  protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
836
                                 int[] spans)
837
  {
838
    int count = getViewCount();
839
    for (int i = 0; i < count; i++)
840
      {
841
        View child = getView(i);
842
        int max = (int) child.getMaximumSpan(axis);
843
        if (max < targetSpan)
844
          {
845
            // Align child when it can't be made as wide as the target span.
846
            float align = child.getAlignment(axis);
847
            offsets[i] = (int) ((targetSpan - max) * align);
848
            spans[i] = max;
849
          }
850
        else
851
          {
852
            // Expand child to target width if possible.
853
            int min = (int) child.getMinimumSpan(axis);
854
            offsets[i] = 0;
855
            spans[i] = Math.max(min, targetSpan);
856
          }
857
      }
858
  }
859
 
860
  /**
861
   * Returns <code>true</code> if the cached allocations for the children
862
   * are still valid, <code>false</code> otherwise.
863
   *
864
   * @return <code>true</code> if the cached allocations for the children
865
   *         are still valid, <code>false</code> otherwise
866
   */
867
  protected boolean isAllocationValid()
868
  {
869
    return isLayoutValid(X_AXIS) && isLayoutValid(Y_AXIS);
870
  }
871
 
872
  /**
873
   * Return the current width of the box. This is the last allocated width.
874
   *
875
   * @return the current width of the box
876
   */
877
  public int getWidth()
878
  {
879
    // The RI returns the following here, however, I'd think that is a bug.
880
    // return span[X_AXIS] + getLeftInset() - getRightInset();
881
    return span[X_AXIS] + getLeftInset() + getRightInset();
882
  }
883
 
884
  /**
885
   * Return the current height of the box. This is the last allocated height.
886
   *
887
   * @return the current height of the box
888
   */
889
  public int getHeight()
890
  {
891
    // The RI returns the following here, however, I'd think that is a bug.
892
    // return span[Y_AXIS] + getTopInset() - getBottomInset();
893
    return span[Y_AXIS] + getTopInset() + getBottomInset();
894
  }
895
 
896
  /**
897
   * Sets the size of the view. If the actual size has changed, the layout
898
   * is updated accordingly.
899
   *
900
   * @param width the new width
901
   * @param height the new height
902
   */
903
  public void setSize(float width, float height)
904
  {
905
    layout((int) (width - getLeftInset() - getRightInset()),
906
           (int) (height - getTopInset() - getBottomInset()));
907
  }
908
 
909
  /**
910
   * Returns the span for the child view with the given index for the specified
911
   * axis.
912
   *
913
   * @param axis the axis to examine, either <code>X_AXIS</code> or
914
   *        <code>Y_AXIS</code>
915
   * @param childIndex the index of the child for for which to return the span
916
   *
917
   * @return the span for the child view with the given index for the specified
918
   *         axis
919
   */
920
  protected int getSpan(int axis, int childIndex)
921
  {
922
    if (axis != X_AXIS && axis != Y_AXIS)
923
      throw new IllegalArgumentException("Illegal axis argument");
924
    return spans[axis][childIndex];
925
  }
926
 
927
  /**
928
   * Returns the offset for the child view with the given index for the
929
   * specified axis.
930
   *
931
   * @param axis the axis to examine, either <code>X_AXIS</code> or
932
   *        <code>Y_AXIS</code>
933
   * @param childIndex the index of the child for for which to return the span
934
   *
935
   * @return the offset for the child view with the given index for the
936
   *         specified axis
937
   */
938
  protected int getOffset(int axis, int childIndex)
939
  {
940
    if (axis != X_AXIS && axis != Y_AXIS)
941
      throw new IllegalArgumentException("Illegal axis argument");
942
    return offsets[axis][childIndex];
943
  }
944
 
945
  /**
946
   * Returns the alignment for this box view for the specified axis. The
947
   * axis that is tiled (the major axis) will be requested to be aligned
948
   * centered (0.5F). The minor axis alignment depends on the child view's
949
   * total alignment.
950
   *
951
   * @param axis the axis which is examined
952
   *
953
   * @return the alignment for this box view for the specified axis
954
   */
955
  public float getAlignment(int axis)
956
  {
957
     updateRequirements(axis);
958
     return requirements[axis].alignment;
959
  }
960
 
961
  /**
962
   * Called by a child View when its preferred span has changed.
963
   *
964
   * @param width indicates that the preferred width of the child changed.
965
   * @param height indicates that the preferred height of the child changed.
966
   * @param child the child View.
967
   */
968
  public void preferenceChanged(View child, boolean width, boolean height)
969
  {
970
    if (width)
971
      {
972
        layoutValid[X_AXIS] = false;
973
        requirementsValid[X_AXIS] = false;
974
      }
975
    if (height)
976
      {
977
        layoutValid[Y_AXIS] = false;
978
        requirementsValid[Y_AXIS] = false;
979
      }
980
    super.preferenceChanged(child, width, height);
981
  }
982
 
983
  /**
984
   * Maps the document model position <code>pos</code> to a Shape
985
   * in the view coordinate space.  This method overrides CompositeView's
986
   * method to make sure the children are allocated properly before
987
   * calling the super's behaviour.
988
   */
989
  public Shape modelToView(int pos, Shape a, Position.Bias bias)
990
      throws BadLocationException
991
  {
992
    // Make sure everything is allocated properly and then call super
993
    if (! isAllocationValid())
994
      {
995
        Rectangle bounds = a.getBounds();
996
        setSize(bounds.width, bounds.height);
997
      }
998
    return super.modelToView(pos, a, bias);
999
  }
1000
 
1001
  /**
1002
   * Returns the resize weight of this view. A value of <code>0</code> or less
1003
   * means this view is not resizeable. Positive values make the view
1004
   * resizeable. This implementation returns <code>0</code> for the major
1005
   * axis and <code>1</code> for the minor axis of this box view.
1006
   *
1007
   * @param axis the axis
1008
   *
1009
   * @return the resizability of this view along the specified axis
1010
   *
1011
   * @throws IllegalArgumentException if <code>axis</code> is invalid
1012
   */
1013
  public int getResizeWeight(int axis)
1014
  {
1015
    if (axis != X_AXIS && axis != Y_AXIS)
1016
      throw new IllegalArgumentException("Illegal axis argument");
1017
    updateRequirements(axis);
1018
    int weight = 0;
1019
    if ((requirements[axis].preferred != requirements[axis].minimum)
1020
        || (requirements[axis].preferred != requirements[axis].maximum))
1021
      weight = 1;
1022
    return weight;
1023
  }
1024
 
1025
  /**
1026
   * Returns the child allocation for the child view with the specified
1027
   * <code>index</code>. If the layout is invalid, this returns
1028
   * <code>null</code>.
1029
   *
1030
   * @param index the child view index
1031
   * @param a the allocation to this view
1032
   *
1033
   * @return the child allocation for the child view with the specified
1034
   *         <code>index</code> or <code>null</code> if the layout is invalid
1035
   *         or <code>a</code> is null
1036
   */
1037
  public Shape getChildAllocation(int index, Shape a)
1038
  {
1039
    Shape ret = null;
1040
    if (isAllocationValid() && a != null)
1041
      ret = super.getChildAllocation(index, a);
1042
    return ret;
1043
  }
1044
 
1045
  protected void forwardUpdate(DocumentEvent.ElementChange ec, DocumentEvent e,
1046
                               Shape a, ViewFactory vf)
1047
  {
1048
    boolean wasValid = isLayoutValid(myAxis);
1049
    super.forwardUpdate(ec, e, a, vf);
1050
    // Trigger repaint when one of the children changed the major axis.
1051
    if (wasValid && ! isLayoutValid(myAxis))
1052
      {
1053
        Container c = getContainer();
1054
        if (a != null && c != null)
1055
          {
1056
            int pos = e.getOffset();
1057
            int index = getViewIndexAtPosition(pos);
1058
            Rectangle r = getInsideAllocation(a);
1059
            if (myAxis == X_AXIS)
1060
              {
1061
                r.x += offsets[myAxis][index];
1062
                r.width -= offsets[myAxis][index];
1063
              }
1064
            else
1065
              {
1066
                r.y += offsets[myAxis][index];
1067
                r.height -= offsets[myAxis][index];
1068
              }
1069
            c.repaint(r.x, r.y, r.width, r.height);
1070
          }
1071
      }
1072
  }
1073
 
1074
  public int viewToModel(float x, float y, Shape a, Position.Bias[] bias)
1075
  {
1076
    if (! isAllocationValid())
1077
      {
1078
        Rectangle r = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
1079
        setSize(r.width, r.height);
1080
      }
1081
    return super.viewToModel(x, y, a, bias);
1082
  }
1083
 
1084
  protected boolean flipEastAndWestAtEnds(int position, Position.Bias bias)
1085
  {
1086
    // FIXME: What to do here?
1087
    return super.flipEastAndWestAtEnds(position, bias);
1088
  }
1089
 
1090
  /**
1091
   * Updates the view's cached requirements along the specified axis if
1092
   * necessary. The requirements are only updated if the layout for the
1093
   * specified axis is marked as invalid.
1094
   *
1095
   * @param axis the axis
1096
   */
1097
  private void updateRequirements(int axis)
1098
  {
1099
    if (axis != Y_AXIS && axis != X_AXIS)
1100
      throw new IllegalArgumentException("Illegal axis: " + axis);
1101
    if (! requirementsValid[axis])
1102
      {
1103
        if (axis == myAxis)
1104
          requirements[axis] = calculateMajorAxisRequirements(axis,
1105
                                                           requirements[axis]);
1106
        else
1107
          requirements[axis] = calculateMinorAxisRequirements(axis,
1108
                                                           requirements[axis]);
1109
        requirementsValid[axis] = true;
1110
      }
1111
  }
1112
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.