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

Subversion Repositories openrisc

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 772 jeremybenn
/* PlainView.java --
2
   Copyright (C) 2004, 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.Color;
42
import java.awt.Component;
43
import java.awt.Font;
44
import java.awt.FontMetrics;
45
import java.awt.Graphics;
46
import java.awt.Rectangle;
47
import java.awt.Shape;
48
 
49
import javax.swing.SwingUtilities;
50
import javax.swing.event.DocumentEvent;
51
import javax.swing.event.DocumentEvent.ElementChange;
52
 
53
public class PlainView extends View implements TabExpander
54
{
55
  Color selectedColor;
56
  Color unselectedColor;
57
 
58
  /**
59
   * The color that is used to draw disabled text fields.
60
   */
61
  Color disabledColor;
62
 
63
  /**
64
   * While painting this is the textcomponent's current start index
65
   * of the selection.
66
   */
67
  int selectionStart;
68
 
69
  /**
70
   * While painting this is the textcomponent's current end index
71
   * of the selection.
72
   */
73
  int selectionEnd;
74
 
75
  Font font;
76
 
77
  /** The length of the longest line in the Document **/
78
  float maxLineLength = -1;
79
 
80
  /** The longest line in the Document **/
81
  Element longestLine = null;
82
 
83
  protected FontMetrics metrics;
84
 
85
  /**
86
   * The instance returned by {@link #getLineBuffer()}.
87
   */
88
  private transient Segment lineBuffer;
89
 
90
  /**
91
   * The base offset for tab calculations.
92
   */
93
  private int tabBase;
94
 
95
  /**
96
   * The tab size.
97
   */
98
  private int tabSize;
99
 
100
  public PlainView(Element elem)
101
  {
102
    super(elem);
103
  }
104
 
105
  /**
106
   * @since 1.4
107
   */
108
  protected void updateMetrics()
109
  {
110
    Component component = getContainer();
111
    Font font = component.getFont();
112
 
113
    if (this.font != font)
114
      {
115
        this.font = font;
116
        metrics = component.getFontMetrics(font);
117
        tabSize = getTabSize() * metrics.charWidth('m');
118
      }
119
  }
120
 
121
  /**
122
   * @since 1.4
123
   */
124
  protected Rectangle lineToRect(Shape a, int line)
125
  {
126
    // Ensure metrics are up-to-date.
127
    updateMetrics();
128
 
129
    Rectangle rect = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
130
    int fontHeight = metrics.getHeight();
131
    return new Rectangle(rect.x, rect.y + (line * fontHeight),
132
                         rect.width, fontHeight);
133
  }
134
 
135
  public Shape modelToView(int position, Shape a, Position.Bias b)
136
    throws BadLocationException
137
  {
138
    // Ensure metrics are up-to-date.
139
    updateMetrics();
140
 
141
    Document document = getDocument();
142
 
143
    // Get rectangle of the line containing position.
144
    int lineIndex = getElement().getElementIndex(position);
145
    Rectangle rect = lineToRect(a, lineIndex);
146
    tabBase = rect.x;
147
 
148
    // Get the rectangle for position.
149
    Element line = getElement().getElement(lineIndex);
150
    int lineStart = line.getStartOffset();
151
    Segment segment = getLineBuffer();
152
    document.getText(lineStart, position - lineStart, segment);
153
    int xoffset = Utilities.getTabbedTextWidth(segment, metrics, tabBase,
154
                                               this, lineStart);
155
 
156
    // Calc the real rectangle.
157
    rect.x += xoffset;
158
    rect.width = 1;
159
    rect.height = metrics.getHeight();
160
 
161
    return rect;
162
  }
163
 
164
  /**
165
   * Draws a line of text. The X and Y coordinates specify the start of
166
   * the <em>baseline</em> of the line.
167
   *
168
   * @param lineIndex the index of the line
169
   * @param g the graphics to use for drawing the text
170
   * @param x the X coordinate of the baseline
171
   * @param y the Y coordinate of the baseline
172
   */
173
  protected void drawLine(int lineIndex, Graphics g, int x, int y)
174
  {
175
    try
176
      {
177
        Element line = getElement().getElement(lineIndex);
178
        int startOffset = line.getStartOffset();
179
        int endOffset = line.getEndOffset() - 1;
180
 
181
        if (selectionStart <= startOffset)
182
          // Selection starts before the line ...
183
          if (selectionEnd <= startOffset)
184
            {
185
              // end ends before the line: Draw completely unselected text.
186
              drawUnselectedText(g, x, y, startOffset, endOffset);
187
            }
188
          else if (selectionEnd <= endOffset)
189
            {
190
              // and ends within the line: First part is selected,
191
              // second is not.
192
              x = drawSelectedText(g, x, y, startOffset, selectionEnd);
193
              drawUnselectedText(g, x, y, selectionEnd, endOffset);
194
            }
195
          else
196
            // and ends behind the line: Draw completely selected text.
197
            drawSelectedText(g, x, y, startOffset, endOffset);
198
        else if (selectionStart < endOffset)
199
          // Selection starts within the line ..
200
          if (selectionEnd < endOffset)
201
            {
202
              // and ends within it: First part unselected, second part
203
              // selected, third part unselected.
204
              x = drawUnselectedText(g, x, y, startOffset, selectionStart);
205
              x = drawSelectedText(g, x, y, selectionStart, selectionEnd);
206
              drawUnselectedText(g, x, y, selectionEnd, endOffset);
207
            }
208
          else
209
            {
210
              // and ends behind the line: First part unselected, second
211
              // part selected.
212
              x = drawUnselectedText(g, x, y, startOffset, selectionStart);
213
              drawSelectedText(g, x, y, selectionStart, endOffset);
214
            }
215
        else
216
          // Selection is behind this line: Draw completely unselected text.
217
          drawUnselectedText(g, x, y, startOffset, endOffset);
218
      }
219
    catch (BadLocationException e)
220
    {
221
      AssertionError ae = new AssertionError("Unexpected bad location");
222
      ae.initCause(e);
223
      throw ae;
224
    }
225
  }
226
 
227
  protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1)
228
    throws BadLocationException
229
  {
230
    g.setColor(selectedColor);
231
    Segment segment = getLineBuffer();
232
    getDocument().getText(p0, p1 - p0, segment);
233
    return Utilities.drawTabbedText(segment, x, y, g, this, segment.offset);
234
  }
235
 
236
  /**
237
   * Draws a chunk of unselected text.
238
   *
239
   * @param g the graphics to use for drawing the text
240
   * @param x the X coordinate of the baseline
241
   * @param y the Y coordinate of the baseline
242
   * @param p0 the start position in the text model
243
   * @param p1 the end position in the text model
244
   *
245
   * @return the X location of the end of the range
246
   *
247
   * @throws BadLocationException if <code>p0</code> or <code>p1</code> are
248
   *         invalid
249
   */
250
  protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1)
251
    throws BadLocationException
252
  {
253
    JTextComponent textComponent = (JTextComponent) getContainer();
254
    if (textComponent.isEnabled())
255
      g.setColor(unselectedColor);
256
    else
257
      g.setColor(disabledColor);
258
 
259
    Segment segment = getLineBuffer();
260
    getDocument().getText(p0, p1 - p0, segment);
261
    return Utilities.drawTabbedText(segment, x, y, g, this, segment.offset);
262
  }
263
 
264
  public void paint(Graphics g, Shape s)
265
  {
266
    // Ensure metrics are up-to-date.
267
    updateMetrics();
268
 
269
    JTextComponent textComponent = (JTextComponent) getContainer();
270
 
271
    selectedColor = textComponent.getSelectedTextColor();
272
    unselectedColor = textComponent.getForeground();
273
    disabledColor = textComponent.getDisabledTextColor();
274
    selectionStart = textComponent.getSelectionStart();
275
    selectionEnd = textComponent.getSelectionEnd();
276
 
277
    Rectangle rect = s instanceof Rectangle ? (Rectangle) s : s.getBounds();
278
    tabBase = rect.x;
279
 
280
    // FIXME: Text may be scrolled.
281
    Document document = textComponent.getDocument();
282
    Element root = getElement();
283
    int height = metrics.getHeight();
284
 
285
    // For layered highlighters we need to paint the layered highlights
286
    // before painting any text.
287
    LayeredHighlighter hl = null;
288
    Highlighter h = textComponent.getHighlighter();
289
    if (h instanceof LayeredHighlighter)
290
      hl = (LayeredHighlighter) h;
291
 
292
    int count = root.getElementCount();
293
 
294
    // Determine first and last line inside the clip.
295
    Rectangle clip = g.getClipBounds();
296
    SwingUtilities.computeIntersection(rect.x, rect.y, rect.width, rect.height,
297
                                       clip);
298
    int line0 = (clip.y - rect.y) / height;
299
    line0 = Math.max(0, Math.min(line0, count - 1));
300
    int line1 = (clip.y + clip.height - rect.y) / height;
301
    line1 = Math.max(0, Math.min(line1, count - 1));
302
    int y = rect.y + metrics.getAscent() + height * line0;
303
    for (int i = line0; i <= line1; i++)
304
      {
305
        if (hl != null)
306
          {
307
            Element lineEl = root.getElement(i);
308
            // Exclude the trailing newline from beeing highlighted.
309
            if (i == count)
310
              hl.paintLayeredHighlights(g, lineEl.getStartOffset(),
311
                                        lineEl.getEndOffset(), s, textComponent,
312
                                        this);
313
            else
314
              hl.paintLayeredHighlights(g, lineEl.getStartOffset(),
315
                                        lineEl.getEndOffset() - 1, s,
316
                                        textComponent, this);
317
          }
318
        drawLine(i, g, rect.x, y);
319
        y += height;
320
      }
321
  }
322
 
323
  /**
324
   * Returns the tab size of a tab.  Checks the Document's
325
   * properties for PlainDocument.tabSizeAttribute and returns it if it is
326
   * defined, otherwise returns 8.
327
   *
328
   * @return the tab size.
329
   */
330
  protected int getTabSize()
331
  {
332
    Object tabSize = getDocument().getProperty(PlainDocument.tabSizeAttribute);
333
    if (tabSize == null)
334
      return 8;
335
    return ((Integer)tabSize).intValue();
336
  }
337
 
338
  /**
339
   * Returns the next tab stop position after a given reference position.
340
   *
341
   * This implementation ignores the <code>tabStop</code> argument.
342
   *
343
   * @param x the current x position in pixels
344
   * @param tabStop the position within the text stream that the tab occured at
345
   */
346
  public float nextTabStop(float x, int tabStop)
347
  {
348
    float next = x;
349
    if (tabSize != 0)
350
      {
351
        int numTabs = (((int) x) - tabBase) / tabSize;
352
        next = tabBase + (numTabs + 1) * tabSize;
353
      }
354
    return next;
355
  }
356
 
357
  /**
358
   * Returns the length of the longest line, used for getting the span
359
   * @return the length of the longest line
360
   */
361
  float determineMaxLineLength()
362
  {
363
    // if the longest line is cached, return the cached value
364
    if (maxLineLength != -1)
365
      return maxLineLength;
366
 
367
    // otherwise we have to go through all the lines and find it
368
    Element el = getElement();
369
    Segment seg = getLineBuffer();
370
    float span = 0;
371
    for (int i = 0; i < el.getElementCount(); i++)
372
      {
373
        Element child = el.getElement(i);
374
        int start = child.getStartOffset();
375
        int end = child.getEndOffset() - 1;
376
        try
377
          {
378
            el.getDocument().getText(start, end - start, seg);
379
          }
380
        catch (BadLocationException ex)
381
          {
382
            AssertionError ae = new AssertionError("Unexpected bad location");
383
            ae.initCause(ex);
384
            throw ae;
385
          }
386
 
387
        if (seg == null || seg.array == null || seg.count == 0)
388
          continue;
389
 
390
        int width = metrics.charsWidth(seg.array, seg.offset, seg.count);
391
        if (width > span)
392
          {
393
            longestLine = child;
394
            span = width;
395
          }
396
      }
397
    maxLineLength = span;
398
    return maxLineLength;
399
  }
400
 
401
  public float getPreferredSpan(int axis)
402
  {
403
    if (axis != X_AXIS && axis != Y_AXIS)
404
      throw new IllegalArgumentException();
405
 
406
    // make sure we have the metrics
407
    updateMetrics();
408
 
409
    Element el = getElement();
410
    float span;
411
 
412
    switch (axis)
413
      {
414
      case X_AXIS:
415
        span = determineMaxLineLength();
416
        break;
417
      case Y_AXIS:
418
      default:
419
        span = metrics.getHeight() * el.getElementCount();
420
        break;
421
      }
422
 
423
    return span;
424
  }
425
 
426
  /**
427
   * Maps coordinates from the <code>View</code>'s space into a position
428
   * in the document model.
429
   *
430
   * @param x the x coordinate in the view space
431
   * @param y the y coordinate in the view space
432
   * @param a the allocation of this <code>View</code>
433
   * @param b the bias to use
434
   *
435
   * @return the position in the document that corresponds to the screen
436
   *         coordinates <code>x, y</code>
437
   */
438
  public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
439
  {
440
    Rectangle rec = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
441
    tabBase = rec.x;
442
 
443
    int pos;
444
    if ((int) y < rec.y)
445
      // Above our area vertically. Return start offset.
446
      pos = getStartOffset();
447
    else if ((int) y > rec.y + rec.height)
448
      // Below our area vertically. Return end offset.
449
      pos = getEndOffset() - 1;
450
    else
451
      {
452
        // Inside the allocation vertically. Determine line and X offset.
453
        Document doc = getDocument();
454
        Element root = doc.getDefaultRootElement();
455
        int line = Math.abs(((int) y - rec.y) / metrics.getHeight());
456
        if (line >= root.getElementCount())
457
          pos = getEndOffset() - 1;
458
        else
459
          {
460
            Element lineEl = root.getElement(line);
461
            if (x < rec.x)
462
              // To the left of the allocation area.
463
              pos = lineEl.getStartOffset();
464
            else if (x > rec.x + rec.width)
465
              // To the right of the allocation area.
466
              pos = lineEl.getEndOffset() - 1;
467
            else
468
              {
469
                try
470
                  {
471
                    int p0 = lineEl.getStartOffset();
472
                    int p1 = lineEl.getEndOffset();
473
                    Segment s = new Segment();
474
                    doc.getText(p0, p1 - p0, s);
475
                    tabBase = rec.x;
476
                    pos = p0 + Utilities.getTabbedTextOffset(s, metrics,
477
                                                             tabBase, (int) x,
478
                                                             this, p0);
479
                  }
480
                catch (BadLocationException ex)
481
                  {
482
                    // Should not happen.
483
                    pos = -1;
484
                  }
485
              }
486
 
487
          }
488
      }
489
    // Bias is always forward.
490
    b[0] = Position.Bias.Forward;
491
    return pos;
492
  }
493
 
494
  /**
495
   * Since insertUpdate and removeUpdate each deal with children
496
   * Elements being both added and removed, they both have to perform
497
   * the same checks.  So they both simply call this method.
498
   * @param changes the DocumentEvent for the changes to the Document.
499
   * @param a the allocation of the View.
500
   * @param f the ViewFactory to use for rebuilding.
501
   */
502
  protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f)
503
  {
504
    // This happens during initialization.
505
    if (metrics == null)
506
      {
507
        updateMetrics();
508
        preferenceChanged(null, true, true);
509
        return;
510
      }
511
 
512
    Element element = getElement();
513
 
514
    // Find longest line if it hasn't been initialized yet.
515
    if (longestLine == null)
516
      findLongestLine(0, element.getElementCount() - 1);
517
 
518
    ElementChange change = changes.getChange(element);
519
    if (changes.getType() == DocumentEvent.EventType.INSERT)
520
      {
521
        // Handles character/line insertion.
522
 
523
        // Determine if lines have been added. In this case we repaint
524
        // differently.
525
        boolean linesAdded = true;
526
        if (change == null)
527
          linesAdded = false;
528
 
529
        // Determine the start line.
530
        int start;
531
        if (linesAdded)
532
          start = change.getIndex();
533
        else
534
          start = element.getElementIndex(changes.getOffset());
535
 
536
        // Determine the length of the updated region.
537
        int length = 0;
538
        if (linesAdded)
539
          length = change.getChildrenAdded().length - 1;
540
 
541
        // Update the longest line and length.
542
        int oldMaxLength = (int) maxLineLength;
543
        if (longestLine.getEndOffset() < changes.getOffset()
544
            || longestLine.getStartOffset() > changes.getOffset()
545
                                             + changes.getLength())
546
          {
547
            findLongestLine(start, start + length);
548
          }
549
        else
550
          {
551
            findLongestLine(0, element.getElementCount() - 1);
552
          }
553
 
554
        // Trigger a preference change so that the layout gets updated
555
        // correctly.
556
        preferenceChanged(null, maxLineLength != oldMaxLength, linesAdded);
557
 
558
        // Damage the updated line range.
559
        int endLine = start;
560
        if (linesAdded)
561
          endLine = element.getElementCount() - 1;
562
        damageLineRange(start, endLine, a, getContainer());
563
 
564
      }
565
    else
566
      {
567
        // Handles character/lines removals.
568
 
569
        // Update the longest line and length and trigger preference changed.
570
        int oldMaxLength = (int) maxLineLength;
571
        if (change != null)
572
          {
573
            // Line(s) have been removed.
574
            findLongestLine(0, element.getElementCount() - 1);
575
            preferenceChanged(null, maxLineLength != oldMaxLength, true);
576
          }
577
        else
578
          {
579
            // No line has been removed.
580
            int lineNo = getElement().getElementIndex(changes.getOffset());
581
            Element line = getElement().getElement(lineNo);
582
            if (longestLine == line)
583
              {
584
                findLongestLine(0, element.getElementCount() - 1);
585
                preferenceChanged(null, maxLineLength != oldMaxLength, false);
586
            }
587
            damageLineRange(lineNo, lineNo, a, getContainer());
588
        }
589
      }
590
  }
591
 
592
  /**
593
   * This method is called when something is inserted into the Document
594
   * that this View is displaying.
595
   *
596
   * @param changes the DocumentEvent for the changes.
597
   * @param a the allocation of the View
598
   * @param f the ViewFactory used to rebuild
599
   */
600
  public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f)
601
  {
602
    updateDamage(changes, a, f);
603
  }
604
 
605
  /**
606
   * This method is called when something is removed from the Document
607
   * that this View is displaying.
608
   *
609
   * @param changes the DocumentEvent for the changes.
610
   * @param a the allocation of the View
611
   * @param f the ViewFactory used to rebuild
612
   */
613
  public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory f)
614
  {
615
    updateDamage(changes, a, f);
616
  }
617
 
618
  /**
619
   * This method is called when attributes were changed in the
620
   * Document in a location that this view is responsible for.
621
   */
622
  public void changedUpdate (DocumentEvent changes, Shape a, ViewFactory f)
623
  {
624
    updateDamage(changes, a, f);
625
  }
626
 
627
  /**
628
   * Repaint the given line range.  This is called from insertUpdate,
629
   * changedUpdate, and removeUpdate when no new lines were added
630
   * and no lines were removed, to repaint the line that was
631
   * modified.
632
   *
633
   * @param line0 the start of the range
634
   * @param line1 the end of the range
635
   * @param a the rendering region of the host
636
   * @param host the Component that uses this View (used to call repaint
637
   * on that Component)
638
   *
639
   * @since 1.4
640
   */
641
  protected void damageLineRange (int line0, int line1, Shape a, Component host)
642
  {
643
    if (a == null)
644
      return;
645
 
646
    Rectangle rec0 = lineToRect(a, line0);
647
    Rectangle rec1 = lineToRect(a, line1);
648
 
649
    if (rec0 == null || rec1 == null)
650
      // something went wrong, repaint the entire host to be safe
651
      host.repaint();
652
    else
653
      {
654
        Rectangle repaintRec = SwingUtilities.computeUnion(rec0.x, rec0.y,
655
                                                           rec0.width,
656
                                                           rec0.height, rec1);
657
        host.repaint(repaintRec.x, repaintRec.y, repaintRec.width,
658
                     repaintRec.height);
659
      }
660
  }
661
 
662
  /**
663
   * Provides a {@link Segment} object, that can be used to fetch text from
664
   * the document.
665
   *
666
   * @returna {@link Segment} object, that can be used to fetch text from
667
   *          the document
668
   */
669
  protected final Segment getLineBuffer()
670
  {
671
    if (lineBuffer == null)
672
      lineBuffer = new Segment();
673
    return lineBuffer;
674
  }
675
 
676
  /**
677
   * Finds and updates the longest line in the view inside an interval of
678
   * lines.
679
   *
680
   * @param start the start of the search interval
681
   * @param end the end of the search interval
682
   */
683
  private void findLongestLine(int start, int end)
684
  {
685
    for (int i = start; i <= end; i++)
686
      {
687
        int w = getLineLength(i);
688
        if (w > maxLineLength)
689
          {
690
            maxLineLength = w;
691
            longestLine = getElement().getElement(i);
692
          }
693
      }
694
  }
695
 
696
  /**
697
   * Determines the length of the specified line.
698
   *
699
   * @param line the number of the line
700
   *
701
   * @return the length of the line in pixels
702
   */
703
  private int getLineLength(int line)
704
  {
705
    Element lineEl = getElement().getElement(line);
706
    Segment buffer = getLineBuffer();
707
    try
708
      {
709
        Document doc = getDocument();
710
        doc.getText(lineEl.getStartOffset(),
711
                    lineEl.getEndOffset() - lineEl.getStartOffset() - 1,
712
                    buffer);
713
      }
714
    catch (BadLocationException ex)
715
      {
716
        AssertionError err = new AssertionError("Unexpected bad location");
717
        err.initCause(ex);
718
        throw err;
719
      }
720
 
721
    return Utilities.getTabbedTextWidth(buffer, metrics, tabBase, this,
722
                                        lineEl.getStartOffset());
723
  }
724
}

powered by: WebSVN 2.1.0

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