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/] [WrappedPlainView.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* WrappedPlainView.java --
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.Color;
42
import java.awt.Container;
43
import java.awt.FontMetrics;
44
import java.awt.Graphics;
45
import java.awt.Rectangle;
46
import java.awt.Shape;
47
 
48
import javax.swing.SwingConstants;
49
import javax.swing.event.DocumentEvent;
50
import javax.swing.text.Position.Bias;
51
 
52
/**
53
 * @author Anthony Balkissoon abalkiss at redhat dot com
54
 *
55
 */
56
public class WrappedPlainView extends BoxView implements TabExpander
57
{
58
  /** The color for selected text **/
59
  Color selectedColor;
60
 
61
  /** The color for unselected text **/
62
  Color unselectedColor;
63
 
64
  /** The color for disabled components **/
65
  Color disabledColor;
66
 
67
  /** Stores the font metrics **/
68
  protected FontMetrics metrics;
69
 
70
  /** Whether or not to wrap on word boundaries **/
71
  boolean wordWrap;
72
 
73
  /** A ViewFactory that creates WrappedLines **/
74
  ViewFactory viewFactory = new WrappedLineCreator();
75
 
76
  /** The start of the selected text **/
77
  int selectionStart;
78
 
79
  /** The end of the selected text **/
80
  int selectionEnd;
81
 
82
  /**
83
   * The instance returned by {@link #getLineBuffer()}.
84
   */
85
  private transient Segment lineBuffer;
86
 
87
  public WrappedPlainView (Element elem)
88
  {
89
    this (elem, false);
90
  }
91
 
92
  public WrappedPlainView (Element elem, boolean wordWrap)
93
  {
94
    super (elem, Y_AXIS);
95
    this.wordWrap = wordWrap;
96
  }
97
 
98
  /**
99
   * Provides access to the Segment used for retrievals from the Document.
100
   * @return the Segment.
101
   */
102
  protected final Segment getLineBuffer()
103
  {
104
    if (lineBuffer == null)
105
      lineBuffer = new Segment();
106
    return lineBuffer;
107
  }
108
 
109
  /**
110
   * Returns the next tab stop position after a given reference position.
111
   *
112
   * This implementation ignores the <code>tabStop</code> argument.
113
   *
114
   * @param x the current x position in pixels
115
   * @param tabStop the position within the text stream that the tab occured at
116
   */
117
  public float nextTabStop(float x, int tabStop)
118
  {
119
    JTextComponent host = (JTextComponent)getContainer();
120
    float tabSizePixels = getTabSize()
121
                          * host.getFontMetrics(host.getFont()).charWidth('m');
122
    return (float) (Math.floor(x / tabSizePixels) + 1) * tabSizePixels;
123
  }
124
 
125
  /**
126
   * Returns the tab size for the Document based on
127
   * PlainDocument.tabSizeAttribute, defaulting to 8 if this property is
128
   * not defined
129
   *
130
   * @return the tab size.
131
   */
132
  protected int getTabSize()
133
  {
134
    Object tabSize = getDocument().getProperty(PlainDocument.tabSizeAttribute);
135
    if (tabSize == null)
136
      return 8;
137
    return ((Integer)tabSize).intValue();
138
  }
139
 
140
  /**
141
   * Draws a line of text, suppressing white space at the end and expanding
142
   * tabs.  Calls drawSelectedText and drawUnselectedText.
143
   * @param p0 starting document position to use
144
   * @param p1 ending document position to use
145
   * @param g graphics context
146
   * @param x starting x position
147
   * @param y starting y position
148
   */
149
  protected void drawLine(int p0, int p1, Graphics g, int x, int y)
150
  {
151
    try
152
    {
153
      // We have to draw both selected and unselected text.  There are
154
      // several cases:
155
      //  - entire range is unselected
156
      //  - entire range is selected
157
      //  - start of range is selected, end of range is unselected
158
      //  - start of range is unselected, end of range is selected
159
      //  - middle of range is selected, start and end of range is unselected
160
 
161
      // entire range unselected:      
162
      if ((selectionStart == selectionEnd) ||
163
          (p0 > selectionEnd || p1 < selectionStart))
164
        drawUnselectedText(g, x, y, p0, p1);
165
 
166
      // entire range selected
167
      else if (p0 >= selectionStart && p1 <= selectionEnd)
168
        drawSelectedText(g, x, y, p0, p1);
169
 
170
      // start of range selected, end of range unselected
171
      else if (p0 >= selectionStart)
172
        {
173
          x = drawSelectedText(g, x, y, p0, selectionEnd);
174
          drawUnselectedText(g, x, y, selectionEnd, p1);
175
        }
176
 
177
      // start of range unselected, end of range selected
178
      else if (selectionStart > p0 && selectionEnd > p1)
179
        {
180
          x = drawUnselectedText(g, x, y, p0, selectionStart);
181
          drawSelectedText(g, x, y, selectionStart, p1);
182
        }
183
 
184
      // middle of range selected
185
      else if (selectionStart > p0)
186
        {
187
          x = drawUnselectedText(g, x, y, p0, selectionStart);
188
          x = drawSelectedText(g, x, y, selectionStart, selectionEnd);
189
          drawUnselectedText(g, x, y, selectionEnd, p1);
190
        }
191
    }
192
    catch (BadLocationException ble)
193
    {
194
      // shouldn't happen
195
    }
196
  }
197
 
198
  /**
199
   * Renders the range of text as selected text.  Just paints the text
200
   * in the color specified by the host component.  Assumes the highlighter
201
   * will render the selected background.
202
   * @param g the graphics context
203
   * @param x the starting X coordinate
204
   * @param y the starting Y coordinate
205
   * @param p0 the starting model location
206
   * @param p1 the ending model location
207
   * @return the X coordinate of the end of the text
208
   * @throws BadLocationException if the given range is invalid
209
   */
210
  protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1)
211
      throws BadLocationException
212
  {
213
    g.setColor(selectedColor);
214
    Segment segment = getLineBuffer();
215
    getDocument().getText(p0, p1 - p0, segment);
216
    return Utilities.drawTabbedText(segment, x, y, g, this, p0);
217
  }
218
 
219
  /**
220
   * Renders the range of text as normal unhighlighted text.
221
   * @param g the graphics context
222
   * @param x the starting X coordinate
223
   * @param y the starting Y coordinate
224
   * @param p0 the starting model location
225
   * @param p1 the end model location
226
   * @return the X location of the end off the range
227
   * @throws BadLocationException if the range given is invalid
228
   */
229
  protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1)
230
      throws BadLocationException
231
  {
232
    JTextComponent textComponent = (JTextComponent) getContainer();
233
    if (textComponent.isEnabled())
234
      g.setColor(unselectedColor);
235
    else
236
      g.setColor(disabledColor);
237
 
238
    Segment segment = getLineBuffer();
239
    getDocument().getText(p0, p1 - p0, segment);
240
    return Utilities.drawTabbedText(segment, x, y, g, this, p0);
241
  }
242
 
243
  /**
244
   * Loads the children to initiate the view.  Called by setParent.
245
   * Creates a WrappedLine for each child Element.
246
   */
247
  protected void loadChildren (ViewFactory f)
248
  {
249
    Element root = getElement();
250
    int numChildren = root.getElementCount();
251
    if (numChildren == 0)
252
      return;
253
 
254
    View[] children = new View[numChildren];
255
    for (int i = 0; i < numChildren; i++)
256
      children[i] = new WrappedLine(root.getElement(i));
257
    replace(0, 0, children);
258
  }
259
 
260
  /**
261
   * Calculates the break position for the text between model positions
262
   * p0 and p1.  Will break on word boundaries or character boundaries
263
   * depending on the break argument given in construction of this
264
   * WrappedPlainView.  Used by the nested WrappedLine class to determine
265
   * when to start the next logical line.
266
   * @param p0 the start model position
267
   * @param p1 the end model position
268
   * @return the model position at which to break the text
269
   */
270
  protected int calculateBreakPosition(int p0, int p1)
271
  {
272
    Container c = getContainer();
273
    Rectangle alloc = c.isValid() ? c.getBounds()
274
                                 : new Rectangle(c.getPreferredSize());
275
    updateMetrics();
276
    try
277
      {
278
        getDocument().getText(p0, p1 - p0, getLineBuffer());
279
      }
280
    catch (BadLocationException ble)
281
      {
282
        // this shouldn't happen
283
      }
284
    // FIXME: Should we account for the insets of the container?
285
    if (wordWrap)
286
      return p0
287
             + Utilities.getBreakLocation(lineBuffer, metrics, alloc.x,
288
                                          alloc.x + alloc.width, this, 0);
289
    else
290
      {
291
      return p0
292
             + Utilities.getTabbedTextOffset(lineBuffer, metrics, alloc.x,
293
                                             alloc.x + alloc.width, this, 0);
294
      }
295
  }
296
 
297
  void updateMetrics()
298
  {
299
    Container component = getContainer();
300
    metrics = component.getFontMetrics(component.getFont());
301
  }
302
 
303
  /**
304
   * Determines the preferred span along the given axis.  Implemented to
305
   * cache the font metrics and then call the super classes method.
306
   */
307
  public float getPreferredSpan (int axis)
308
  {
309
    updateMetrics();
310
    return super.getPreferredSpan(axis);
311
  }
312
 
313
  /**
314
   * Determines the minimum span along the given axis.  Implemented to
315
   * cache the font metrics and then call the super classes method.
316
   */
317
  public float getMinimumSpan (int axis)
318
  {
319
    updateMetrics();
320
    return super.getMinimumSpan(axis);
321
  }
322
 
323
  /**
324
   * Determines the maximum span along the given axis.  Implemented to
325
   * cache the font metrics and then call the super classes method.
326
   */
327
  public float getMaximumSpan (int axis)
328
  {
329
    updateMetrics();
330
    return super.getMaximumSpan(axis);
331
  }
332
 
333
  /**
334
   * Called when something was inserted.  Overridden so that
335
   * the view factory creates WrappedLine views.
336
   */
337
  public void insertUpdate (DocumentEvent e, Shape a, ViewFactory f)
338
  {
339
    super.insertUpdate(e, a, viewFactory);
340
    // FIXME: could improve performance by repainting only the necessary area
341
    getContainer().repaint();
342
  }
343
 
344
  /**
345
   * Called when something is removed.  Overridden so that
346
   * the view factory creates WrappedLine views.
347
   */
348
  public void removeUpdate (DocumentEvent e, Shape a, ViewFactory f)
349
  {
350
    super.removeUpdate(e, a, viewFactory);
351
    // FIXME: could improve performance by repainting only the necessary area
352
    getContainer().repaint();
353
  }
354
 
355
  /**
356
   * Called when the portion of the Document that this View is responsible
357
   * for changes.  Overridden so that the view factory creates
358
   * WrappedLine views.
359
   */
360
  public void changedUpdate (DocumentEvent e, Shape a, ViewFactory f)
361
  {
362
    super.changedUpdate(e, a, viewFactory);
363
    // FIXME: could improve performance by repainting only the necessary area
364
    getContainer().repaint();
365
  }
366
 
367
  class WrappedLineCreator implements ViewFactory
368
  {
369
    // Creates a new WrappedLine
370
    public View create(Element elem)
371
    {
372
      return new WrappedLine(elem);
373
    }
374
  }
375
 
376
  /**
377
   * Renders the <code>Element</code> that is associated with this
378
   * <code>View</code>.  Caches the metrics and then calls
379
   * super.paint to paint all the child views.
380
   *
381
   * @param g the <code>Graphics</code> context to render to
382
   * @param a the allocated region for the <code>Element</code>
383
   */
384
  public void paint(Graphics g, Shape a)
385
  {
386
    JTextComponent comp = (JTextComponent)getContainer();
387
    selectionStart = comp.getSelectionStart();
388
    selectionEnd = comp.getSelectionEnd();
389
    updateMetrics();
390
    super.paint(g, a);
391
  }
392
 
393
  /**
394
   * Sets the size of the View.  Implemented to update the metrics
395
   * and then call super method.
396
   */
397
  public void setSize (float width, float height)
398
  {
399
    updateMetrics();
400
    if (width != getWidth())
401
      preferenceChanged(null, true, true);
402
    super.setSize(width, height);
403
  }
404
 
405
  class WrappedLine extends View
406
  {
407
    /** Used to cache the number of lines for this View **/
408
    int numLines;
409
 
410
    public WrappedLine(Element elem)
411
    {
412
      super(elem);
413
      determineNumLines();
414
    }
415
 
416
    /**
417
     * Renders this (possibly wrapped) line using the given Graphics object
418
     * and on the given rendering surface.
419
     */
420
    public void paint(Graphics g, Shape s)
421
    {
422
      // Ensure metrics are up-to-date.
423
      updateMetrics();
424
      JTextComponent textComponent = (JTextComponent) getContainer();
425
 
426
      g.setFont(textComponent.getFont());
427
      selectedColor = textComponent.getSelectedTextColor();
428
      unselectedColor = textComponent.getForeground();
429
      disabledColor = textComponent.getDisabledTextColor();
430
 
431
      // FIXME: this is a hack, for some reason textComponent.getSelectedColor
432
      // was returning black, which is not visible against a black background
433
      selectedColor = Color.WHITE;
434
 
435
      Rectangle rect = s.getBounds();
436
      int lineHeight = metrics.getHeight();
437
 
438
      int end = getEndOffset();
439
      int currStart = getStartOffset();
440
      int currEnd;
441
      while (currStart < end)
442
        {
443
          currEnd = calculateBreakPosition(currStart, end);
444
          drawLine(currStart, currEnd, g, rect.x, rect.y);
445
          rect.y += lineHeight;
446
          if (currEnd == currStart)
447
            currStart ++;
448
          else
449
            currStart = currEnd;
450
        }
451
    }
452
 
453
    /**
454
     * Determines the number of logical lines that the Element
455
     * needs to be displayed
456
     * @return the number of lines needed to display the Element
457
     */
458
    int determineNumLines()
459
    {
460
      numLines = 0;
461
      int end = getEndOffset();
462
      if (end == 0)
463
        return 0;
464
 
465
      int breakPoint;
466
      for (int i = getStartOffset(); i < end;)
467
        {
468
          numLines ++;
469
          // careful: check that there's no off-by-one problem here
470
          // depending on which position calculateBreakPosition returns
471
          breakPoint = calculateBreakPosition(i, end);
472
          if (breakPoint == i)
473
            i ++;
474
          else
475
            i = breakPoint;
476
        }
477
      return numLines;
478
    }
479
 
480
    /**
481
     * Determines the preferred span for this view along the given axis.
482
     *
483
     * @param axis the axis (either X_AXIS or Y_AXIS)
484
     *
485
     * @return the preferred span along the given axis.
486
     * @throws IllegalArgumentException if axis is not X_AXIS or Y_AXIS
487
     */
488
    public float getPreferredSpan(int axis)
489
    {
490
      if (axis == X_AXIS)
491
        return getWidth();
492
      else if (axis == Y_AXIS)
493
        return numLines * metrics.getHeight();
494
 
495
      throw new IllegalArgumentException("Invalid axis for getPreferredSpan: "
496
                                         + axis);
497
    }
498
 
499
    /**
500
     * Provides a mapping from model space to view space.
501
     *
502
     * @param pos the position in the model
503
     * @param a the region into which the view is rendered
504
     * @param b the position bias (forward or backward)
505
     *
506
     * @return a box in view space that represents the given position
507
     * in model space
508
     * @throws BadLocationException if the given model position is invalid
509
     */
510
    public Shape modelToView(int pos, Shape a, Bias b)
511
        throws BadLocationException
512
    {
513
      Segment s = getLineBuffer();
514
      int lineHeight = metrics.getHeight();
515
      Rectangle rect = a.getBounds();
516
 
517
      // Return a rectangle with width 1 and height equal to the height 
518
      // of the text
519
      rect.height = lineHeight;
520
      rect.width = 1;
521
 
522
      int currLineStart = getStartOffset();
523
      int end = getEndOffset();
524
 
525
      if (pos < currLineStart || pos >= end)
526
        throw new BadLocationException("invalid offset", pos);
527
 
528
      while (true)
529
        {
530
          int currLineEnd = calculateBreakPosition(currLineStart, end);
531
          // If pos is between currLineStart and currLineEnd then just find
532
          // the width of the text from currLineStart to pos and add that
533
          // to rect.x
534
          if (pos >= currLineStart && pos < currLineEnd || pos == end - 1)
535
            {
536
              try
537
                {
538
                  getDocument().getText(currLineStart, pos - currLineStart, s);
539
                }
540
              catch (BadLocationException ble)
541
                {
542
                  // Shouldn't happen
543
                }
544
              rect.x += Utilities.getTabbedTextWidth(s, metrics, rect.x,
545
                                                     WrappedPlainView.this,
546
                                                     currLineStart);
547
              return rect;
548
            }
549
          // Increment rect.y so we're checking the next logical line
550
          rect.y += lineHeight;
551
 
552
          // Increment currLineStart to the model position of the start
553
          // of the next logical line
554
          if (currLineEnd == currLineStart)
555
            currLineStart = end;
556
          else
557
            currLineStart = currLineEnd;
558
        }
559
 
560
    }
561
 
562
    /**
563
     * Provides a mapping from view space to model space.
564
     *
565
     * @param x the x coordinate in view space
566
     * @param y the y coordinate in view space
567
     * @param a the region into which the view is rendered
568
     * @param b the position bias (forward or backward)
569
     *
570
     * @return the location in the model that best represents the
571
     * given point in view space
572
     */
573
    public int viewToModel(float x, float y, Shape a, Bias[] b)
574
    {
575
      Segment s = getLineBuffer();
576
      Rectangle rect = a.getBounds();
577
      int currLineStart = getStartOffset();
578
      int end = getEndOffset();
579
      int lineHeight = metrics.getHeight();
580
      if (y < rect.y)
581
        return currLineStart;
582
      if (y > rect.y + rect.height)
583
        return end - 1;
584
 
585
      while (true)
586
        {
587
          int currLineEnd = calculateBreakPosition(currLineStart, end);
588
          // If we're at the right y-position that means we're on the right
589
          // logical line and we should look for the character
590
          if (y >= rect.y && y < rect.y + lineHeight)
591
            {
592
              // Check if the x position is to the left or right of the text
593
              if (x < rect.x)
594
                return currLineStart;
595
              if (x > rect.x + rect.width)
596
                return currLineEnd - 1;
597
 
598
              try
599
                {
600
                  getDocument().getText(currLineStart, end - currLineStart, s);
601
                }
602
              catch (BadLocationException ble)
603
                {
604
                  // Shouldn't happen
605
                }
606
              int mark = Utilities.getTabbedTextOffset(s, metrics, rect.x,
607
                                                       (int) x,
608
                                                       WrappedPlainView.this,
609
                                                       currLineStart);
610
              return currLineStart + mark;
611
            }
612
          // Increment rect.y so we're checking the next logical line
613
          rect.y += lineHeight;
614
 
615
          // Increment currLineStart to the model position of the start
616
          // of the next logical line
617
          if (currLineEnd == currLineStart)
618
            currLineStart = end;
619
          else
620
            currLineStart = currLineEnd;
621
        }
622
    }
623
 
624
    /**
625
     * Returns the document position that is (visually) nearest to the given
626
     * document position <code>pos</code> in the given direction <code>d</code>.
627
     *
628
     * @param c the text component
629
     * @param pos the document position
630
     * @param b the bias for <code>pos</code>
631
     * @param d the direction, must be either {@link SwingConstants#NORTH},
632
     *        {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or
633
     *        {@link SwingConstants#EAST}
634
     * @param biasRet an array of {@link Position.Bias} that can hold at least
635
     *        one element, which is filled with the bias of the return position
636
     *        on method exit
637
     *
638
     * @return the document position that is (visually) nearest to the given
639
     *         document position <code>pos</code> in the given direction
640
     *         <code>d</code>
641
     *
642
     * @throws BadLocationException if <code>pos</code> is not a valid offset
643
     *         in the document model
644
     */
645
    public int getNextVisualPositionFrom(JTextComponent c, int pos,
646
                                         Position.Bias b, int d,
647
                                         Position.Bias[] biasRet)
648
      throws BadLocationException
649
    {
650
      // TODO: Implement this properly.
651
      throw new AssertionError("Not implemented yet.");
652
    }
653
 
654
    /**
655
     * This method is called from insertUpdate and removeUpdate.
656
     * If the number of lines in the document has changed, just repaint
657
     * the whole thing (note, could improve performance by not repainting
658
     * anything above the changes).  If the number of lines hasn't changed,
659
     * just repaint the given Rectangle.
660
     * @param a the Rectangle to repaint if the number of lines hasn't changed
661
     */
662
    void updateDamage (Rectangle a)
663
    {
664
      int newNumLines = determineNumLines();
665
      if (numLines != newNumLines)
666
        {
667
          numLines = newNumLines;
668
          getContainer().repaint();
669
        }
670
      else
671
        getContainer().repaint(a.x, a.y, a.width, a.height);
672
    }
673
 
674
    /**
675
     * This method is called when something is inserted into the Document
676
     * that this View is displaying.
677
     *
678
     * @param changes the DocumentEvent for the changes.
679
     * @param a the allocation of the View
680
     * @param f the ViewFactory used to rebuild
681
     */
682
    public void insertUpdate (DocumentEvent changes, Shape a, ViewFactory f)
683
    {
684
      updateDamage((Rectangle)a);
685
    }
686
 
687
    /**
688
     * This method is called when something is removed from the Document
689
     * that this View is displaying.
690
     *
691
     * @param changes the DocumentEvent for the changes.
692
     * @param a the allocation of the View
693
     * @param f the ViewFactory used to rebuild
694
     */
695
    public void removeUpdate (DocumentEvent changes, Shape a, ViewFactory f)
696
    {
697
      updateDamage((Rectangle)a);
698
    }
699
  }
700
}

powered by: WebSVN 2.1.0

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