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

Subversion Repositories openrisc

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 772 jeremybenn
/* Utilities.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.FontMetrics;
42
import java.awt.Graphics;
43
import java.awt.Point;
44
import java.text.BreakIterator;
45
 
46
import javax.swing.text.Position.Bias;
47
 
48
/**
49
 * A set of utilities to deal with text. This is used by several other classes
50
 * inside this package.
51
 *
52
 * @author Roman Kennke (roman@ontographics.com)
53
 * @author Robert Schuster (robertschuster@fsfe.org)
54
 */
55
public class Utilities
56
{
57
 
58
  /**
59
   * Creates a new <code>Utilities</code> object.
60
   */
61
  public Utilities()
62
  {
63
    // Nothing to be done here.
64
  }
65
 
66
  /**
67
   * Draws the given text segment. Contained tabs and newline characters
68
   * are taken into account. Tabs are expanded using the
69
   * specified {@link TabExpander}.
70
   *
71
   *
72
   * The X and Y coordinates denote the start of the <em>baseline</em> where
73
   * the text should be drawn.
74
   *
75
   * @param s the text fragment to be drawn.
76
   * @param x the x position for drawing.
77
   * @param y the y position for drawing.
78
   * @param g the {@link Graphics} context for drawing.
79
   * @param e the {@link TabExpander} which specifies the Tab-expanding
80
   *     technique.
81
   * @param startOffset starting offset in the text.
82
   * @return the x coordinate at the end of the drawn text.
83
   */
84
  public static final int drawTabbedText(Segment s, int x, int y, Graphics g,
85
                                         TabExpander e, int startOffset)
86
  {
87
    // This buffers the chars to be drawn.
88
    char[] buffer = s.array;
89
 
90
    // The font metrics of the current selected font.
91
    FontMetrics metrics = g.getFontMetrics();
92
 
93
    int ascent = metrics.getAscent();
94
 
95
    // The current x and y pixel coordinates.
96
    int pixelX = x;
97
 
98
    int pos = s.offset;
99
    int len = 0;
100
 
101
    int end = s.offset + s.count;
102
 
103
    for (int offset = s.offset; offset < end; ++offset)
104
      {
105
        char c = buffer[offset];
106
        switch (c)
107
          {
108
          case '\t':
109
            if (len > 0) {
110
              g.drawChars(buffer, pos, len, pixelX, y);
111
              pixelX += metrics.charsWidth(buffer, pos, len);
112
              len = 0;
113
            }
114
            pos = offset+1;
115
            if (e != null)
116
              pixelX = (int) e.nextTabStop((float) pixelX, startOffset + offset
117
                                           - s.offset);
118
            else
119
              pixelX += metrics.charWidth(' ');
120
            x = pixelX;
121
            break;
122
          case '\n':
123
          case '\r':
124
            if (len > 0) {
125
              g.drawChars(buffer, pos, len, pixelX, y);
126
              pixelX += metrics.charsWidth(buffer, pos, len);
127
              len = 0;
128
            }
129
            x = pixelX;
130
            break;
131
          default:
132
            len += 1;
133
          }
134
      }
135
 
136
    if (len > 0)
137
      {
138
        g.drawChars(buffer, pos, len, pixelX, y);
139
        pixelX += metrics.charsWidth(buffer, pos, len);
140
      }
141
 
142
    return pixelX;
143
  }
144
 
145
  /**
146
   * Determines the width, that the given text <code>s</code> would take
147
   * if it was printed with the given {@link java.awt.FontMetrics} on the
148
   * specified screen position.
149
   * @param s the text fragment
150
   * @param metrics the font metrics of the font to be used
151
   * @param x the x coordinate of the point at which drawing should be done
152
   * @param e the {@link TabExpander} to be used
153
   * @param startOffset the index in <code>s</code> where to start
154
   * @returns the width of the given text s. This takes tabs and newlines
155
   * into account.
156
   */
157
  public static final int getTabbedTextWidth(Segment s, FontMetrics metrics,
158
                                             int x, TabExpander e,
159
                                             int startOffset)
160
  {
161
    // This buffers the chars to be drawn.
162
    char[] buffer = s.array;
163
 
164
    // The current x coordinate.
165
    int pixelX = x;
166
 
167
    // The current maximum width.
168
    int maxWidth = 0;
169
 
170
    int end = s.offset + s.count;
171
    int count = 0;
172
    for (int offset = s.offset; offset < end; offset++)
173
      {
174
        switch (buffer[offset])
175
          {
176
          case '\t':
177
            // In case we have a tab, we just 'jump' over the tab.
178
            // When we have no tab expander we just use the width of 'm'.
179
            if (e != null)
180
              pixelX = (int) e.nextTabStop(pixelX,
181
                                           startOffset + offset - s.offset);
182
            else
183
              pixelX += metrics.charWidth(' ');
184
            break;
185
          case '\n':
186
            // In case we have a newline, we must 'draw'
187
            // the buffer and jump on the next line.
188
            pixelX += metrics.charsWidth(buffer, offset - count, count);
189
            count = 0;
190
            break;
191
          default:
192
            count++;
193
          }
194
      }
195
 
196
    // Take the last line into account.
197
    pixelX += metrics.charsWidth(buffer, end - count, count);
198
 
199
    return pixelX - x;
200
  }
201
 
202
  /**
203
   * Provides a facility to map screen coordinates into a model location. For a
204
   * given text fragment and start location within this fragment, this method
205
   * determines the model location so that the resulting fragment fits best
206
   * into the span <code>[x0, x]</code>.
207
   *
208
   * The parameter <code>round</code> controls which model location is returned
209
   * if the view coordinates are on a character: If <code>round</code> is
210
   * <code>true</code>, then the result is rounded up to the next character, so
211
   * that the resulting fragment is the smallest fragment that is larger than
212
   * the specified span. If <code>round</code> is <code>false</code>, then the
213
   * resulting fragment is the largest fragment that is smaller than the
214
   * specified span.
215
   *
216
   * @param s the text segment
217
   * @param fm the font metrics to use
218
   * @param x0 the starting screen location
219
   * @param x the target screen location at which the requested fragment should
220
   *        end
221
   * @param te the tab expander to use; if this is <code>null</code>, TABs are
222
   *        expanded to one space character
223
   * @param p0 the starting model location
224
   * @param round if <code>true</code> round up to the next location, otherwise
225
   *        round down to the current location
226
   *
227
   * @return the model location, so that the resulting fragment fits within the
228
   *         specified span
229
   */
230
  public static final int getTabbedTextOffset(Segment s, FontMetrics fm, int x0,
231
                                              int x, TabExpander te, int p0,
232
                                              boolean round)
233
  {
234
    int found = s.count;
235
    int currentX = x0;
236
    int nextX = currentX;
237
 
238
    int end = s.offset + s.count;
239
    for (int pos = s.offset; pos < end && found == s.count; pos++)
240
      {
241
        char nextChar = s.array[pos];
242
 
243
        if (nextChar != '\t')
244
          nextX += fm.charWidth(nextChar);
245
        else
246
          {
247
            if (te == null)
248
              nextX += fm.charWidth(' ');
249
            else
250
              nextX += ((int) te.nextTabStop(nextX, p0 + pos - s.offset));
251
          }
252
 
253
        if (x >= currentX && x < nextX)
254
          {
255
            // Found position.
256
            if ((! round) || ((x - currentX) < (nextX - x)))
257
              {
258
                found = pos - s.offset;
259
              }
260
            else
261
              {
262
                found = pos + 1 - s.offset;
263
              }
264
          }
265
        currentX = nextX;
266
      }
267
 
268
    return found;
269
  }
270
 
271
  /**
272
   * Provides a facility to map screen coordinates into a model location. For a
273
   * given text fragment and start location within this fragment, this method
274
   * determines the model location so that the resulting fragment fits best
275
   * into the span <code>[x0, x]</code>.
276
   *
277
   * This method rounds up to the next location, so that the resulting fragment
278
   * will be the smallest fragment of the text, that is greater than the
279
   * specified span.
280
   *
281
   * @param s the text segment
282
   * @param fm the font metrics to use
283
   * @param x0 the starting screen location
284
   * @param x the target screen location at which the requested fragment should
285
   *        end
286
   * @param te the tab expander to use; if this is <code>null</code>, TABs are
287
   *        expanded to one space character
288
   * @param p0 the starting model location
289
   *
290
   * @return the model location, so that the resulting fragment fits within the
291
   *         specified span
292
   */
293
  public static final int getTabbedTextOffset(Segment s, FontMetrics fm, int x0,
294
                                              int x, TabExpander te, int p0)
295
  {
296
    return getTabbedTextOffset(s, fm, x0, x, te, p0, true);
297
  }
298
 
299
  /**
300
   * Finds the start of the next word for the given offset.
301
   *
302
   * @param c
303
   *          the text component
304
   * @param offs
305
   *          the offset in the document
306
   * @return the location in the model of the start of the next word.
307
   * @throws BadLocationException
308
   *           if the offset is invalid.
309
   */
310
  public static final int getNextWord(JTextComponent c, int offs)
311
      throws BadLocationException
312
  {
313
    if (offs < 0 || offs > (c.getText().length() - 1))
314
      throw new BadLocationException("invalid offset specified", offs);
315
    String text = c.getText();
316
    BreakIterator wb = BreakIterator.getWordInstance();
317
    wb.setText(text);
318
 
319
    int last = wb.following(offs);
320
    int current = wb.next();
321
    int cp;
322
 
323
    while (current != BreakIterator.DONE)
324
      {
325
        for (int i = last; i < current; i++)
326
          {
327
            cp = text.codePointAt(i);
328
 
329
            // Return the last found bound if there is a letter at the current
330
            // location or is not whitespace (meaning it is a number or
331
            // punctuation). The first case means that 'last' denotes the
332
            // beginning of a word while the second case means it is the start
333
            // of something else.
334
            if (Character.isLetter(cp)
335
                || !Character.isWhitespace(cp))
336
              return last;
337
          }
338
        last = current;
339
        current = wb.next();
340
      }
341
 
342
    throw new BadLocationException("no more words", offs);
343
  }
344
 
345
  /**
346
   * Finds the start of the previous word for the given offset.
347
   *
348
   * @param c
349
   *          the text component
350
   * @param offs
351
   *          the offset in the document
352
   * @return the location in the model of the start of the previous word.
353
   * @throws BadLocationException
354
   *           if the offset is invalid.
355
   */
356
  public static final int getPreviousWord(JTextComponent c, int offs)
357
      throws BadLocationException
358
  {
359
    String text = c.getText();
360
 
361
    if (offs <= 0 || offs > text.length())
362
      throw new BadLocationException("invalid offset specified", offs);
363
 
364
    BreakIterator wb = BreakIterator.getWordInstance();
365
    wb.setText(text);
366
    int last = wb.preceding(offs);
367
    int current = wb.previous();
368
    int cp;
369
 
370
    while (current != BreakIterator.DONE)
371
      {
372
        for (int i = last; i < offs; i++)
373
          {
374
            cp = text.codePointAt(i);
375
 
376
            // Return the last found bound if there is a letter at the current
377
            // location or is not whitespace (meaning it is a number or
378
            // punctuation). The first case means that 'last' denotes the
379
            // beginning of a word while the second case means it is the start
380
            // of some else.
381
            if (Character.isLetter(cp)
382
                || !Character.isWhitespace(cp))
383
              return last;
384
          }
385
        last = current;
386
        current = wb.previous();
387
      }
388
 
389
    return 0;
390
  }
391
 
392
  /**
393
   * Finds the start of a word for the given location.
394
   * @param c the text component
395
   * @param offs the offset location
396
   * @return the location of the word beginning
397
   * @throws BadLocationException if the offset location is invalid
398
   */
399
  public static final int getWordStart(JTextComponent c, int offs)
400
      throws BadLocationException
401
  {
402
    String text = c.getText();
403
 
404
    if (offs < 0 || offs > text.length())
405
      throw new BadLocationException("invalid offset specified", offs);
406
 
407
    BreakIterator wb = BreakIterator.getWordInstance();
408
    wb.setText(text);
409
 
410
    if (wb.isBoundary(offs))
411
      return offs;
412
 
413
    return wb.preceding(offs);
414
  }
415
 
416
  /**
417
   * Finds the end of a word for the given location.
418
   * @param c the text component
419
   * @param offs the offset location
420
   * @return the location of the word end
421
   * @throws BadLocationException if the offset location is invalid
422
   */
423
  public static final int getWordEnd(JTextComponent c, int offs)
424
      throws BadLocationException
425
  {
426
    if (offs < 0 || offs >= c.getText().length())
427
      throw new BadLocationException("invalid offset specified", offs);
428
 
429
    String text = c.getText();
430
    BreakIterator wb = BreakIterator.getWordInstance();
431
    wb.setText(text);
432
    return wb.following(offs);
433
  }
434
 
435
  /**
436
   * Get the model position of the end of the row that contains the
437
   * specified model position.  Return null if the given JTextComponent
438
   * does not have a size.
439
   * @param c the JTextComponent
440
   * @param offs the model position
441
   * @return the model position of the end of the row containing the given
442
   * offset
443
   * @throws BadLocationException if the offset is invalid
444
   */
445
  public static final int getRowEnd(JTextComponent c, int offs)
446
      throws BadLocationException
447
  {
448
    String text = c.getText();
449
    if (text == null)
450
      return -1;
451
 
452
    // Do a binary search for the smallest position X > offs
453
    // such that that character at positino X is not on the same
454
    // line as the character at position offs
455
    int high = offs + ((text.length() - 1 - offs) / 2);
456
    int low = offs;
457
    int oldHigh = text.length() + 1;
458
    while (true)
459
      {
460
        if (c.modelToView(high).y != c.modelToView(offs).y)
461
          {
462
            oldHigh = high;
463
            high = low + ((high + 1 - low) / 2);
464
            if (oldHigh == high)
465
              return high - 1;
466
          }
467
        else
468
          {
469
            low = high;
470
            high += ((oldHigh - high) / 2);
471
            if (low == high)
472
              return low;
473
          }
474
      }
475
  }
476
 
477
  /**
478
   * Get the model position of the start of the row that contains the specified
479
   * model position. Return null if the given JTextComponent does not have a
480
   * size.
481
   *
482
   * @param c the JTextComponent
483
   * @param offs the model position
484
   * @return the model position of the start of the row containing the given
485
   *         offset
486
   * @throws BadLocationException if the offset is invalid
487
   */
488
  public static final int getRowStart(JTextComponent c, int offs)
489
      throws BadLocationException
490
  {
491
    String text = c.getText();
492
    if (text == null)
493
      return -1;
494
 
495
    // Do a binary search for the greatest position X < offs
496
    // such that the character at position X is not on the same
497
    // row as the character at position offs
498
    int high = offs;
499
    int low = 0;
500
    int oldLow = 0;
501
    while (true)
502
      {
503
        if (c.modelToView(low).y != c.modelToView(offs).y)
504
          {
505
            oldLow = low;
506
            low = high - ((high + 1 - low) / 2);
507
            if (oldLow == low)
508
              return low + 1;
509
          }
510
        else
511
          {
512
            high = low;
513
            low -= ((low - oldLow) / 2);
514
            if (low == high)
515
              return low;
516
          }
517
      }
518
  }
519
 
520
  /**
521
   * Determine where to break the text in the given Segment, attempting to find
522
   * a word boundary.
523
   * @param s the Segment that holds the text
524
   * @param metrics the font metrics used for calculating the break point
525
   * @param x0 starting view location representing the start of the text
526
   * @param x the target view location
527
   * @param e the TabExpander used for expanding tabs (if this is null tabs
528
   * are expanded to 1 space)
529
   * @param startOffset the offset in the Document of the start of the text
530
   * @return the offset at which we should break the text
531
   */
532
  public static final int getBreakLocation(Segment s, FontMetrics metrics,
533
                                           int x0, int x, TabExpander e,
534
                                           int startOffset)
535
  {
536
    int mark = Utilities.getTabbedTextOffset(s, metrics, x0, x, e, startOffset,
537
                                             false);
538
    int breakLoc = mark;
539
    // If mark is equal to the end of the string, just use that position.
540
    if (mark < s.count - 1)
541
      {
542
        for (int i = s.offset + mark; i >= s.offset; i--)
543
          {
544
            char ch = s.array[i];
545
            if (ch < 256)
546
              {
547
                // For ASCII simply scan backwards for whitespace.
548
                if (Character.isWhitespace(ch))
549
                  {
550
                    breakLoc = i - s.offset + 1;
551
                    break;
552
                  }
553
              }
554
            else
555
              {
556
                // Only query BreakIterator for complex chars.
557
                BreakIterator bi = BreakIterator.getLineInstance();
558
                bi.setText(s);
559
                int pos = bi.preceding(i + 1);
560
                if (pos > s.offset)
561
                  {
562
                    breakLoc = breakLoc - s.offset;
563
                  }
564
                break;
565
              }
566
          }
567
      }
568
    return breakLoc;
569
  }
570
 
571
  /**
572
   * Returns the paragraph element in the text component <code>c</code> at
573
   * the specified location <code>offset</code>.
574
   *
575
   * @param c the text component
576
   * @param offset the offset of the paragraph element to return
577
   *
578
   * @return the paragraph element at <code>offset</code>
579
   */
580
  public static final Element getParagraphElement(JTextComponent c, int offset)
581
  {
582
    Document doc = c.getDocument();
583
    Element par = null;
584
    if (doc instanceof StyledDocument)
585
      {
586
        StyledDocument styledDoc = (StyledDocument) doc;
587
        par = styledDoc.getParagraphElement(offset);
588
      }
589
    else
590
      {
591
        Element root = c.getDocument().getDefaultRootElement();
592
        int parIndex = root.getElementIndex(offset);
593
        par = root.getElement(parIndex);
594
      }
595
    return par;
596
  }
597
 
598
  /**
599
   * Returns the document position that is closest above to the specified x
600
   * coordinate in the row containing <code>offset</code>.
601
   *
602
   * @param c the text component
603
   * @param offset the offset
604
   * @param x the x coordinate
605
   *
606
   * @return  the document position that is closest above to the specified x
607
   *          coordinate in the row containing <code>offset</code>
608
   *
609
   * @throws BadLocationException if <code>offset</code> is not a valid offset
610
   */
611
  public static final int getPositionAbove(JTextComponent c, int offset, int x)
612
    throws BadLocationException
613
  {
614
    int offs = getRowStart(c, offset);
615
 
616
    if(offs == -1)
617
      return -1;
618
 
619
    // Effectively calculates the y value of the previous line.
620
    Point pt = c.modelToView(offs-1).getLocation();
621
 
622
    pt.x = x;
623
 
624
    // Calculate a simple fitting offset.
625
    offs = c.viewToModel(pt);
626
 
627
    // Find out the real x positions of the calculated character and its
628
    // neighbour.
629
    int offsX = c.modelToView(offs).getLocation().x;
630
    int offsXNext = c.modelToView(offs+1).getLocation().x;
631
 
632
    // Chose the one which is nearer to us and return its offset.
633
    if (Math.abs(offsX-x) <= Math.abs(offsXNext-x))
634
      return offs;
635
    else
636
      return offs+1;
637
  }
638
 
639
  /**
640
   * Returns the document position that is closest below to the specified x
641
   * coordinate in the row containing <code>offset</code>.
642
   *
643
   * @param c the text component
644
   * @param offset the offset
645
   * @param x the x coordinate
646
   *
647
   * @return  the document position that is closest above to the specified x
648
   *          coordinate in the row containing <code>offset</code>
649
   *
650
   * @throws BadLocationException if <code>offset</code> is not a valid offset
651
   */
652
  public static final int getPositionBelow(JTextComponent c, int offset, int x)
653
    throws BadLocationException
654
  {
655
    int offs = getRowEnd(c, offset);
656
 
657
    if(offs == -1)
658
      return -1;
659
 
660
    Point pt = null;
661
 
662
    // Note: Some views represent the position after the last
663
    // typed character others do not. Converting offset 3 in "a\nb"
664
    // in a PlainView will return a valid rectangle while in a
665
    // WrappedPlainView this will throw a BadLocationException.
666
    // This behavior has been observed in the RI.
667
    try
668
      {
669
        // Effectively calculates the y value of the next line.
670
        pt = c.modelToView(offs+1).getLocation();
671
      }
672
    catch(BadLocationException ble)
673
      {
674
        return offset;
675
      }
676
 
677
    pt.x = x;
678
 
679
    // Calculate a simple fitting offset.
680
    offs = c.viewToModel(pt);
681
 
682
    if (offs == c.getDocument().getLength())
683
      return offs;
684
 
685
    // Find out the real x positions of the calculated character and its
686
    // neighbour.
687
    int offsX = c.modelToView(offs).getLocation().x;
688
    int offsXNext = c.modelToView(offs+1).getLocation().x;
689
 
690
    // Chose the one which is nearer to us and return its offset.
691
    if (Math.abs(offsX-x) <= Math.abs(offsXNext-x))
692
      return offs;
693
    else
694
      return offs+1;
695
    }
696
 
697
  /** This is an internal helper method which is used by the
698
   * <code>javax.swing.text</code> package. It simply delegates the
699
   * call to a method with the same name on the <code>NavigationFilter</code>
700
   * of the provided <code>JTextComponent</code> (if it has one) or its UI.
701
   *
702
   * If the underlying method throws a <code>BadLocationException</code> it
703
   * will be swallowed and the initial offset is returned.
704
   */
705
  static int getNextVisualPositionFrom(JTextComponent t, int offset, int direction)
706
  {
707
    NavigationFilter nf = t.getNavigationFilter();
708
 
709
    try
710
      {
711
        return (nf != null)
712
          ? nf.getNextVisualPositionFrom(t,
713
                                         offset,
714
                                         Bias.Forward,
715
                                         direction,
716
                                         new Position.Bias[1])
717
          : t.getUI().getNextVisualPositionFrom(t,
718
                                                offset,
719
                                                Bias.Forward,
720
                                                direction,
721
                                                new Position.Bias[1]);
722
      }
723
    catch (BadLocationException ble)
724
    {
725
      return offset;
726
    }
727
 
728
  }
729
 
730
}

powered by: WebSVN 2.1.0

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