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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [classpath/] [javax/] [swing/] [text/] [FlowView.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* FlowView.java -- A composite View
2
   Copyright (C) 2005  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
import java.util.Iterator;
46
import java.util.Vector;
47
 
48
import javax.swing.SwingConstants;
49
import javax.swing.event.DocumentEvent;
50
 
51
/**
52
 * A <code>View</code> that can flows it's children into it's layout space.
53
 *
54
 * The <code>FlowView</code> manages a set of logical views (that are
55
 * the children of the {@link #layoutPool} field). These are translated
56
 * at layout time into a set of physical views. These are the views that
57
 * are managed as the real child views. Each of these child views represents
58
 * a row and are laid out within a box using the superclasses behaviour.
59
 * The concrete implementation of the rows must be provided by subclasses.
60
 *
61
 * @author Roman Kennke (roman@kennke.org)
62
 */
63
public abstract class FlowView extends BoxView
64
{
65
  /**
66
   * A strategy for translating the logical views of a <code>FlowView</code>
67
   * into the real views.
68
   */
69
  public static class FlowStrategy
70
  {
71
    /**
72
     * Creates a new instance of <code>FlowStragegy</code>.
73
     */
74
    public FlowStrategy()
75
    {
76
      // Nothing to do here.
77
    }
78
 
79
    /**
80
     * Receives notification from a <code>FlowView</code> that some content
81
     * has been inserted into the document at a location that the
82
     * <code>FlowView</code> is responsible for.
83
     *
84
     * The default implementation simply calls {@link #layout}.
85
     *
86
     * @param fv the flow view that sends the notification
87
     * @param e the document event describing the change
88
     * @param alloc the current allocation of the flow view
89
     */
90
    public void insertUpdate(FlowView fv, DocumentEvent e, Rectangle alloc)
91
    {
92
      layout(fv);
93
    }
94
 
95
    /**
96
     * Receives notification from a <code>FlowView</code> that some content
97
     * has been removed from the document at a location that the
98
     * <code>FlowView</code> is responsible for.
99
     *
100
     * The default implementation simply calls {@link #layout}.
101
     *
102
     * @param fv the flow view that sends the notification
103
     * @param e the document event describing the change
104
     * @param alloc the current allocation of the flow view
105
     */
106
    public void removeUpdate(FlowView fv, DocumentEvent e, Rectangle alloc)
107
    {
108
      layout(fv);
109
    }
110
 
111
    /**
112
     * Receives notification from a <code>FlowView</code> that some attributes
113
     * have changed in the document at a location that the
114
     * <code>FlowView</code> is responsible for.
115
     *
116
     * The default implementation simply calls {@link #layout}.
117
     *
118
     * @param fv the flow view that sends the notification
119
     * @param e the document event describing the change
120
     * @param alloc the current allocation of the flow view
121
     */
122
    public void changedUpdate(FlowView fv, DocumentEvent e, Rectangle alloc)
123
    {
124
      layout(fv);
125
    }
126
 
127
    /**
128
     * Returns the logical view of the managed <code>FlowView</code>.
129
     *
130
     * @param fv the flow view for which to return the logical view
131
     *
132
     * @return the logical view of the managed <code>FlowView</code>
133
     */
134
    public View getLogicalView(FlowView fv)
135
    {
136
      return fv.layoutPool;
137
    }
138
 
139
    /**
140
     * Performs the layout for the whole view. By default this rebuilds
141
     * all the physical views from the logical views of the managed FlowView.
142
     *
143
     * This is called by {@link FlowView#layout} to update the layout of
144
     * the view.
145
     *
146
     * @param fv the flow view for which we perform the layout
147
     */
148
    public void layout(FlowView fv)
149
    {
150
      fv.removeAll();
151
      Element el = fv.getElement();
152
 
153
      int rowStart = el.getStartOffset();
154
      int end = el.getEndOffset();
155
      int rowIndex = 0;
156
      while (rowStart >= 0 && rowStart < end)
157
        {
158
          View row = fv.createRow();
159
          fv.append(row);
160
          rowStart = layoutRow(fv, rowIndex, rowStart);
161
          rowIndex++;
162
        }
163
    }
164
 
165
    /**
166
     * Lays out one row of the flow view. This is called by {@link #layout}
167
     * to fill one row with child views until the available span is exhausted.
168
     *
169
     * @param fv the flow view for which we perform the layout
170
     * @param rowIndex the index of the row
171
     * @param pos the start position for the row
172
     *
173
     * @return the start position of the next row
174
     */
175
    protected int layoutRow(FlowView fv, int rowIndex, int pos)
176
    {
177
      int spanLeft = fv.getFlowSpan(rowIndex);
178
      if (spanLeft <= 0)
179
        return -1;
180
 
181
      int offset = pos;
182
      View row = fv.getView(rowIndex);
183
      int flowAxis = fv.getFlowAxis();
184
 
185
      while (spanLeft > 0)
186
        {
187
          View child = createView(fv, offset, spanLeft, rowIndex);
188
          if (child == null)
189
            {
190
              offset = -1;
191
              break;
192
            }
193
 
194
          int span = (int) child.getPreferredSpan(flowAxis);
195
          if (span > spanLeft)
196
            {
197
              offset = -1;
198
              break;
199
            }
200
 
201
          row.append(child);
202
          spanLeft -= span;
203
          offset = child.getEndOffset();
204
        }
205
      return offset;
206
    }
207
 
208
    /**
209
     * Creates physical views that form the rows of the flow view. This
210
     * can be an entire view from the logical view (if it fits within the
211
     * available span), a fragment of such a view (if it doesn't fit in the
212
     * available span and can be broken down) or <code>null</code> (if it does
213
     * not fit in the available span and also cannot be broken down).
214
     *
215
     * @param fv the flow view
216
     * @param offset the start offset for the view to be created
217
     * @param spanLeft the available span
218
     * @param rowIndex the index of the row
219
     *
220
     * @return a view to fill the row with, or <code>null</code> if there
221
     *         is no view or view fragment that fits in the available span
222
     */
223
    protected View createView(FlowView fv, int offset, int spanLeft,
224
                              int rowIndex)
225
    {
226
      // Find the logical element for the given offset.
227
      View logicalView = getLogicalView(fv);
228
 
229
      int viewIndex = logicalView.getViewIndex(offset, Position.Bias.Forward);
230
      if (viewIndex == -1)
231
        return null;
232
 
233
      View child = logicalView.getView(viewIndex);
234
      int flowAxis = fv.getFlowAxis();
235
      int span = (int) child.getPreferredSpan(flowAxis);
236
 
237
      if (span <= spanLeft)
238
        return child;
239
      else if (child.getBreakWeight(flowAxis, offset, spanLeft)
240
               > BadBreakWeight)
241
        // FIXME: What to do with the pos parameter here?
242
        return child.breakView(flowAxis, offset, 0, spanLeft);
243
      else
244
        return null;
245
    }
246
  }
247
 
248
  /**
249
   * This special subclass of <code>View</code> is used to represent
250
   * the logical representation of this view. It does not support any
251
   * visual representation, this is handled by the physical view implemented
252
   * in the <code>FlowView</code>.
253
   */
254
  class LogicalView extends View
255
  {
256
    /**
257
     * The child views of this logical view.
258
     */
259
    Vector children;
260
 
261
    /**
262
     * Creates a new LogicalView instance.
263
     */
264
    LogicalView(Element el)
265
    {
266
      super(el);
267
      children = new Vector();
268
    }
269
 
270
    /**
271
     * Returns the container that holds this view. The logical view returns
272
     * the enclosing FlowView's container here.
273
     *
274
     * @return the container that holds this view
275
     */
276
    public Container getContainer()
277
    {
278
      return FlowView.this.getContainer();
279
    }
280
 
281
    /**
282
     * Returns the number of child views of this logical view.
283
     *
284
     * @return the number of child views of this logical view
285
     */
286
    public int getViewCount()
287
    {
288
      return children.size();
289
    }
290
 
291
    /**
292
     * Returns the child view at the specified index.
293
     *
294
     * @param index the index
295
     *
296
     * @return the child view at the specified index
297
     */
298
    public View getView(int index)
299
    {
300
      return (View) children.get(index);
301
    }
302
 
303
    /**
304
     * Replaces some child views with other child views.
305
     *
306
     * @param offset the offset at which to replace child views
307
     * @param length the number of children to remove
308
     * @param views the views to be inserted
309
     */
310
    public void replace(int offset, int length, View[] views)
311
    {
312
      if (length > 0)
313
        {
314
          for (int count = 0; count < length; ++count)
315
            children.remove(offset);
316
        }
317
 
318
      int endOffset = offset + views.length;
319
      for (int i = offset; i < endOffset; ++i)
320
        {
321
          children.add(i, views[i - offset]);
322
          // Set the parent of the child views to the flow view itself so
323
          // it has something to resolve.
324
          views[i - offset].setParent(FlowView.this);
325
        }
326
    }
327
 
328
    /**
329
     * Returns the index of the child view that contains the specified
330
     * position in the document model.
331
     *
332
     * @param pos the position for which we are searching the child view
333
     * @param b the bias
334
     *
335
     * @return the index of the child view that contains the specified
336
     *         position in the document model
337
     */
338
    public int getViewIndex(int pos, Position.Bias b)
339
    {
340
      int index = -1;
341
      int i = 0;
342
      for (Iterator it = children.iterator(); it.hasNext(); i++)
343
        {
344
          View child = (View) it.next();
345
          if (child.getStartOffset() >= pos
346
              && child.getEndOffset() < pos)
347
            {
348
              index = i;
349
              break;
350
            }
351
        }
352
      return index;
353
    }
354
 
355
    /**
356
     * Throws an AssertionError because it must never be called. LogicalView
357
     * only serves as a holder for child views and has no visual
358
     * representation.
359
     */
360
    public float getPreferredSpan(int axis)
361
    {
362
      throw new AssertionError("This method must not be called in "
363
                               + "LogicalView.");
364
    }
365
 
366
    /**
367
     * Throws an AssertionError because it must never be called. LogicalView
368
     * only serves as a holder for child views and has no visual
369
     * representation.
370
     */
371
    public Shape modelToView(int pos, Shape a, Position.Bias b)
372
      throws BadLocationException
373
    {
374
      throw new AssertionError("This method must not be called in "
375
                               + "LogicalView.");
376
    }
377
 
378
    /**
379
     * Throws an AssertionError because it must never be called. LogicalView
380
     * only serves as a holder for child views and has no visual
381
     * representation.
382
     */
383
    public void paint(Graphics g, Shape s)
384
    {
385
      throw new AssertionError("This method must not be called in "
386
                               + "LogicalView.");
387
    }
388
 
389
    /**
390
     * Throws an AssertionError because it must never be called. LogicalView
391
     * only serves as a holder for child views and has no visual
392
     * representation.
393
     */
394
    public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
395
    {
396
      throw new AssertionError("This method must not be called in "
397
                               + "LogicalView.");
398
    }
399
 
400
    /**
401
     * Returns the document position that is (visually) nearest to the given
402
     * document position <code>pos</code> in the given direction <code>d</code>.
403
     *
404
     * @param c the text component
405
     * @param pos the document position
406
     * @param b the bias for <code>pos</code>
407
     * @param d the direction, must be either {@link SwingConstants#NORTH},
408
     *        {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or
409
     *        {@link SwingConstants#EAST}
410
     * @param biasRet an array of {@link Position.Bias} that can hold at least
411
     *        one element, which is filled with the bias of the return position
412
     *        on method exit
413
     *
414
     * @return the document position that is (visually) nearest to the given
415
     *         document position <code>pos</code> in the given direction
416
     *         <code>d</code>
417
     *
418
     * @throws BadLocationException if <code>pos</code> is not a valid offset in
419
     *         the document model
420
     */
421
    public int getNextVisualPositionFrom(JTextComponent c, int pos,
422
                                         Position.Bias b, int d,
423
                                         Position.Bias[] biasRet)
424
      throws BadLocationException
425
    {
426
      assert false : "getNextVisualPositionFrom() must not be called in "
427
        + "LogicalView";
428
      return 0;
429
    }
430
  }
431
 
432
  /**
433
   * The shared instance of FlowStrategy.
434
   */
435
  static final FlowStrategy sharedStrategy = new FlowStrategy();
436
 
437
  /**
438
   * The span of the <code>FlowView</code> that should be flowed.
439
   */
440
  protected int layoutSpan;
441
 
442
  /**
443
   * Represents the logical child elements of this view, encapsulated within
444
   * one parent view (an instance of a package private <code>LogicalView</code>
445
   * class). These will be translated to a set of real views that are then
446
   * displayed on screen. This translation is performed by the inner class
447
   * {@link FlowStrategy}.
448
   */
449
  protected View layoutPool;
450
 
451
  /**
452
   * The <code>FlowStrategy</code> to use for translating between the
453
   * logical and physical view.
454
   */
455
  protected FlowStrategy strategy;
456
 
457
  /**
458
   * Creates a new <code>FlowView</code> for the given
459
   * <code>Element</code> and <code>axis</code>.
460
   *
461
   * @param element the element that is rendered by this FlowView
462
   * @param axis the axis along which the view is tiled, either
463
   *        <code>View.X_AXIS</code> or <code>View.Y_AXIS</code>, the flow
464
   *        axis is orthogonal to this one
465
   */
466
  public FlowView(Element element, int axis)
467
  {
468
    super(element, axis);
469
    strategy = sharedStrategy;
470
  }
471
 
472
  /**
473
   * Returns the axis along which the view should be flowed. This is
474
   * orthogonal to the axis along which the boxes are tiled.
475
   *
476
   * @return the axis along which the view should be flowed
477
   */
478
  public int getFlowAxis()
479
  {
480
    int axis = getAxis();
481
    int flowAxis;
482
 
483
    if (axis == X_AXIS)
484
      flowAxis = Y_AXIS;
485
    else
486
      flowAxis = X_AXIS;
487
 
488
    return flowAxis;
489
 
490
  }
491
 
492
  /**
493
   * Returns the span of the flow for the specified child view. A flow
494
   * layout can be shaped by providing different span values for different
495
   * child indices. The default implementation returns the entire available
496
   * span inside the view.
497
   *
498
   * @param index the index of the child for which to return the span
499
   *
500
   * @return the span of the flow for the specified child view
501
   */
502
  public int getFlowSpan(int index)
503
  {
504
    return layoutSpan;
505
  }
506
 
507
  /**
508
   * Returns the location along the flow axis where the flow span starts
509
   * given a child view index. The flow can be shaped by providing
510
   * different values here.
511
   *
512
   * @param index the index of the child for which to return the flow location
513
   *
514
   * @return the location along the flow axis where the flow span starts
515
   */
516
  public int getFlowStart(int index)
517
  {
518
    return getLeftInset(); // TODO: Is this correct?
519
  }
520
 
521
  /**
522
   * Creates a new view that represents a row within a flow.
523
   *
524
   * @return a view for a new row
525
   */
526
  protected abstract View createRow();
527
 
528
  /**
529
   * Loads the children of this view. The <code>FlowView</code> does not
530
   * directly load its children. Instead it creates a logical view
531
   * (@{link #layoutPool}) which is filled by the logical child views.
532
   * The real children are created at layout time and each represent one
533
   * row.
534
   *
535
   * This method is called by {@link View#setParent} in order to initialize
536
   * the view.
537
   *
538
   * @param vf the view factory to use for creating the child views
539
   */
540
  protected void loadChildren(ViewFactory vf)
541
  {
542
    if (layoutPool == null)
543
      {
544
        layoutPool = new LogicalView(getElement());
545
 
546
        Element el = getElement();
547
        int count = el.getElementCount();
548
        for (int i = 0; i < count; ++i)
549
          {
550
            Element childEl = el.getElement(i);
551
            View childView = vf.create(childEl);
552
            layoutPool.append(childView);
553
          }
554
      }
555
  }
556
 
557
  /**
558
   * Performs the layout of this view. If the span along the flow axis changed,
559
   * this first calls {@link FlowStrategy#layout} in order to rebuild the
560
   * rows of this view. Then the superclass's behaviour is called to arrange
561
   * the rows within the box.
562
   *
563
   * @param width the width of the view
564
   * @param height the height of the view
565
   */
566
  protected void layout(int width, int height)
567
  {
568
    boolean rebuild = false;
569
 
570
    int flowAxis = getFlowAxis();
571
    if (flowAxis == X_AXIS)
572
      {
573
        rebuild = !(width == layoutSpan);
574
        layoutSpan = width;
575
      }
576
    else
577
      {
578
        rebuild = !(height == layoutSpan);
579
        layoutSpan = height;
580
      }
581
 
582
    if (rebuild)
583
      strategy.layout(this);
584
 
585
    // TODO: If the span along the box axis has changed in the process of
586
    // relayouting the rows (that is, if rows have been added or removed),
587
    // call preferenceChanged in order to throw away cached layout information
588
    // of the surrounding BoxView.
589
 
590
    super.layout(width, height);
591
  }
592
 
593
  /**
594
   * Receice notification that some content has been inserted in the region
595
   * that this view is responsible for. This calls
596
   * {@link FlowStrategy#insertUpdate}.
597
   *
598
   * @param changes the document event describing the changes
599
   * @param a the current allocation of the view
600
   * @param vf the view factory that is used for creating new child views
601
   */
602
  public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory vf)
603
  {
604
    // First we must send the insertUpdate to the logical view so it can
605
    // be updated accordingly.
606
    layoutPool.insertUpdate(changes, a, vf);
607
    strategy.insertUpdate(this, changes, getInsideAllocation(a));
608
  }
609
 
610
  /**
611
   * Receice notification that some content has been removed from the region
612
   * that this view is responsible for. This calls
613
   * {@link FlowStrategy#removeUpdate}.
614
   *
615
   * @param changes the document event describing the changes
616
   * @param a the current allocation of the view
617
   * @param vf the view factory that is used for creating new child views
618
   */
619
  public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory vf)
620
  {
621
    strategy.removeUpdate(this, changes, getInsideAllocation(a));
622
  }
623
 
624
  /**
625
   * Receice notification that some attributes changed in the region
626
   * that this view is responsible for. This calls
627
   * {@link FlowStrategy#changedUpdate}.
628
   *
629
   * @param changes the document event describing the changes
630
   * @param a the current allocation of the view
631
   * @param vf the view factory that is used for creating new child views
632
   */
633
  public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory vf)
634
  {
635
    strategy.changedUpdate(this, changes, getInsideAllocation(a));
636
  }
637
 
638
  /**
639
   * Returns the index of the child <code>View</code> for the given model
640
   * position.
641
   *
642
   * This is implemented to iterate over the children of this
643
   * view (the rows) and return the index of the first view that contains
644
   * the given position.
645
   *
646
   * @param pos the model position for whicht the child <code>View</code> is
647
   *        queried
648
   *
649
   * @return the index of the child <code>View</code> for the given model
650
   *         position
651
   */
652
  protected int getViewIndexAtPosition(int pos)
653
  {
654
    // First make sure we have a valid layout.
655
    if (!isAllocationValid())
656
      layout(getWidth(), getHeight());
657
 
658
    int count = getViewCount();
659
    int result = -1;
660
 
661
    for (int i = 0; i < count; ++i)
662
      {
663
        View child = getView(i);
664
        int start = child.getStartOffset();
665
        int end = child.getEndOffset();
666
        if (start <= pos && end > pos)
667
          {
668
            result = i;
669
            break;
670
          }
671
      }
672
    return result;
673
  }
674
}

powered by: WebSVN 2.1.0

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