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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* Utilities.java --
2
   Copyright (C) 2004, 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.FontMetrics;
42
import java.awt.Graphics;
43
import java.awt.Point;
44
import java.awt.Rectangle;
45
import java.text.BreakIterator;
46
 
47
import javax.swing.SwingConstants;
48
 
49
/**
50
 * A set of utilities to deal with text. This is used by several other classes
51
 * inside this package.
52
 *
53
 * @author Roman Kennke (roman@ontographics.com)
54
 */
55
public class Utilities
56
{
57
  /**
58
   * The length of the char buffer that holds the characters to be drawn.
59
   */
60
  private static final int BUF_LENGTH = 64;
61
 
62
  /**
63
   * Creates a new <code>Utilities</code> object.
64
   */
65
  public Utilities()
66
  {
67
    // Nothing to be done here.
68
  }
69
 
70
  /**
71
   * Draws the given text segment. Contained tabs and newline characters
72
   * are taken into account. Tabs are expanded using the
73
   * specified {@link TabExpander}.
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
 
91
    // The current x and y pixel coordinates.
92
    int pixelX = x;
93
    int pixelY = y;
94
 
95
    // The font metrics of the current selected font.
96
    FontMetrics metrics = g.getFontMetrics();
97
    int ascent = metrics.getAscent();
98
 
99
    int pixelWidth = 0;
100
    int pos = s.offset;
101
    int len = 0;
102
 
103
    for (int offset = s.offset; offset < (s.offset + s.count); ++offset)
104
      {
105
        char c = buffer[offset];
106
        if (c == '\t' || c == '\n')
107
          {
108
            if (len > 0) {
109
              g.drawChars(buffer, pos, len, pixelX, pixelY + ascent);
110
              pixelX += pixelWidth;
111
              pixelWidth = 0;
112
            }
113
            pos = offset+1;
114
            len = 0;
115
          }
116
 
117
        switch (c)
118
          {
119
          case '\t':
120
            // In case we have a tab, we just 'jump' over the tab.
121
            // When we have no tab expander we just use the width of ' '.
122
            if (e != null)
123
              pixelX = (int) e.nextTabStop((float) pixelX,
124
                                           startOffset + offset - s.offset);
125
            else
126
              pixelX += metrics.charWidth(' ');
127
            break;
128
          case '\n':
129
            // In case we have a newline, we must jump to the next line.
130
            pixelY += metrics.getHeight();
131
            pixelX = x;
132
            break;
133
          default:
134
            ++len;
135
            pixelWidth += metrics.charWidth(buffer[offset]);
136
            break;
137
          }
138
      }
139
 
140
    if (len > 0)
141
      g.drawChars(buffer, pos, len, pixelX, pixelY + ascent);
142
 
143
    return pixelX;
144
  }
145
 
146
  /**
147
   * Determines the width, that the given text <code>s</code> would take
148
   * if it was printed with the given {@link java.awt.FontMetrics} on the
149
   * specified screen position.
150
   * @param s the text fragment
151
   * @param metrics the font metrics of the font to be used
152
   * @param x the x coordinate of the point at which drawing should be done
153
   * @param e the {@link TabExpander} to be used
154
   * @param startOffset the index in <code>s</code> where to start
155
   * @returns the width of the given text s. This takes tabs and newlines
156
   * into account.
157
   */
158
  public static final int getTabbedTextWidth(Segment s, FontMetrics metrics,
159
                                             int x, TabExpander e,
160
                                             int startOffset)
161
  {
162
    // This buffers the chars to be drawn.
163
    char[] buffer = s.array;
164
 
165
    // The current x coordinate.
166
    int pixelX = x;
167
 
168
    // The current maximum width.
169
    int maxWidth = 0;
170
 
171
    for (int offset = s.offset; offset < (s.offset + s.count); ++offset)
172
      {
173
        switch (buffer[offset])
174
          {
175
          case '\t':
176
            // In case we have a tab, we just 'jump' over the tab.
177
            // When we have no tab expander we just use the width of 'm'.
178
            if (e != null)
179
              pixelX = (int) e.nextTabStop((float) pixelX,
180
                                           startOffset + offset - s.offset);
181
            else
182
              pixelX += metrics.charWidth(' ');
183
            break;
184
          case '\n':
185
            // In case we have a newline, we must 'draw'
186
            // the buffer and jump on the next line.
187
            pixelX += metrics.charWidth(buffer[offset]);
188
            maxWidth = Math.max(maxWidth, pixelX - x);
189
            pixelX = x;
190
            break;
191
          default:
192
            // Here we draw the char.
193
            pixelX += metrics.charWidth(buffer[offset]);
194
            break;
195
          }
196
      }
197
 
198
    // Take the last line into account.
199
    maxWidth = Math.max(maxWidth, pixelX - x);
200
 
201
    return maxWidth;
202
  }
203
 
204
  /**
205
   * Provides a facility to map screen coordinates into a model location. For a
206
   * given text fragment and start location within this fragment, this method
207
   * determines the model location so that the resulting fragment fits best
208
   * into the span <code>[x0, x]</code>.
209
   *
210
   * The parameter <code>round</code> controls which model location is returned
211
   * if the view coordinates are on a character: If <code>round</code> is
212
   * <code>true</code>, then the result is rounded up to the next character, so
213
   * that the resulting fragment is the smallest fragment that is larger than
214
   * the specified span. If <code>round</code> is <code>false</code>, then the
215
   * resulting fragment is the largest fragment that is smaller than the
216
   * specified span.
217
   *
218
   * @param s the text segment
219
   * @param fm the font metrics to use
220
   * @param x0 the starting screen location
221
   * @param x the target screen location at which the requested fragment should
222
   *        end
223
   * @param te the tab expander to use; if this is <code>null</code>, TABs are
224
   *        expanded to one space character
225
   * @param p0 the starting model location
226
   * @param round if <code>true</code> round up to the next location, otherwise
227
   *        round down to the current location
228
   *
229
   * @return the model location, so that the resulting fragment fits within the
230
   *         specified span
231
   */
232
  public static final int getTabbedTextOffset(Segment s, FontMetrics fm, int x0,
233
                                              int x, TabExpander te, int p0,
234
                                              boolean round)
235
  {
236
    // At the end of the for loop, this holds the requested model location
237
    int pos;
238
    int currentX = x0;
239
 
240
    for (pos = p0; pos < s.count; pos++)
241
      {
242
        char nextChar = s.array[s.offset+pos];
243
        if (nextChar == 0)
244
          {
245
            if (! round)
246
              pos--;
247
            break;
248
          }
249
        if (nextChar != '\t')
250
          currentX += fm.charWidth(nextChar);
251
        else
252
          {
253
            if (te == null)
254
              currentX += fm.charWidth(' ');
255
            else
256
              currentX = (int) te.nextTabStop(currentX, pos);
257
          }
258
        if (currentX > x)
259
          {
260
            if (! round)
261
              pos--;
262
            break;
263
          }
264
      }
265
    return pos;
266
  }
267
 
268
  /**
269
   * Provides a facility to map screen coordinates into a model location. For a
270
   * given text fragment and start location within this fragment, this method
271
   * determines the model location so that the resulting fragment fits best
272
   * into the span <code>[x0, x]</code>.
273
   *
274
   * This method rounds up to the next location, so that the resulting fragment
275
   * will be the smallest fragment of the text, that is greater than the
276
   * specified span.
277
   *
278
   * @param s the text segment
279
   * @param fm the font metrics to use
280
   * @param x0 the starting screen location
281
   * @param x the target screen location at which the requested fragment should
282
   *        end
283
   * @param te the tab expander to use; if this is <code>null</code>, TABs are
284
   *        expanded to one space character
285
   * @param p0 the starting model location
286
   *
287
   * @return the model location, so that the resulting fragment fits within the
288
   *         specified span
289
   */
290
  public static final int getTabbedTextOffset(Segment s, FontMetrics fm, int x0,
291
                                              int x, TabExpander te, int p0)
292
  {
293
    return getTabbedTextOffset(s, fm, x0, x, te, p0, true);
294
  }
295
 
296
  /**
297
   * Finds the start of the next word for the given offset.
298
   *
299
   * @param c
300
   *          the text component
301
   * @param offs
302
   *          the offset in the document
303
   * @return the location in the model of the start of the next word.
304
   * @throws BadLocationException
305
   *           if the offset is invalid.
306
   */
307
  public static final int getNextWord(JTextComponent c, int offs)
308
      throws BadLocationException
309
  {
310
    if (offs < 0 || offs > (c.getText().length() - 1))
311
      throw new BadLocationException("invalid offset specified", offs);
312
    String text = c.getText();
313
    BreakIterator wb = BreakIterator.getWordInstance();
314
    wb.setText(text);
315
    int last = wb.following(offs);
316
    int current = wb.next();
317
    while (current != BreakIterator.DONE)
318
      {
319
        for (int i = last; i < current; i++)
320
          {
321
            // FIXME: Should use isLetter(int) and text.codePointAt(int)
322
            // instead, but isLetter(int) isn't implemented yet
323
            if (Character.isLetter(text.charAt(i)))
324
              return last;
325
          }
326
        last = current;
327
        current = wb.next();
328
      }
329
    return BreakIterator.DONE;
330
  }
331
 
332
  /**
333
   * Finds the start of the previous word for the given offset.
334
   *
335
   * @param c
336
   *          the text component
337
   * @param offs
338
   *          the offset in the document
339
   * @return the location in the model of the start of the previous word.
340
   * @throws BadLocationException
341
   *           if the offset is invalid.
342
   */
343
  public static final int getPreviousWord(JTextComponent c, int offs)
344
      throws BadLocationException
345
  {
346
    if (offs < 0 || offs > (c.getText().length() - 1))
347
      throw new BadLocationException("invalid offset specified", offs);
348
    String text = c.getText();
349
    BreakIterator wb = BreakIterator.getWordInstance();
350
    wb.setText(text);
351
    int last = wb.preceding(offs);
352
    int current = wb.previous();
353
 
354
    while (current != BreakIterator.DONE)
355
      {
356
        for (int i = last; i < offs; i++)
357
          {
358
            // FIXME: Should use isLetter(int) and text.codePointAt(int)
359
            // instead, but isLetter(int) isn't implemented yet
360
            if (Character.isLetter(text.charAt(i)))
361
              return last;
362
          }
363
        last = current;
364
        current = wb.previous();
365
      }
366
    return 0;
367
  }
368
 
369
  /**
370
   * Finds the start of a word for the given location.
371
   * @param c the text component
372
   * @param offs the offset location
373
   * @return the location of the word beginning
374
   * @throws BadLocationException if the offset location is invalid
375
   */
376
  public static final int getWordStart(JTextComponent c, int offs)
377
      throws BadLocationException
378
  {
379
    if (offs < 0 || offs >= c.getText().length())
380
      throw new BadLocationException("invalid offset specified", offs);
381
 
382
    String text = c.getText();
383
    BreakIterator wb = BreakIterator.getWordInstance();
384
    wb.setText(text);
385
    if (wb.isBoundary(offs))
386
      return offs;
387
    return wb.preceding(offs);
388
  }
389
 
390
  /**
391
   * Finds the end of a word for the given location.
392
   * @param c the text component
393
   * @param offs the offset location
394
   * @return the location of the word end
395
   * @throws BadLocationException if the offset location is invalid
396
   */
397
  public static final int getWordEnd(JTextComponent c, int offs)
398
      throws BadLocationException
399
  {
400
    if (offs < 0 || offs >= c.getText().length())
401
      throw new BadLocationException("invalid offset specified", offs);
402
 
403
    String text = c.getText();
404
    BreakIterator wb = BreakIterator.getWordInstance();
405
    wb.setText(text);
406
    return wb.following(offs);
407
  }
408
 
409
  /**
410
   * Get the model position of the end of the row that contains the
411
   * specified model position.  Return null if the given JTextComponent
412
   * does not have a size.
413
   * @param c the JTextComponent
414
   * @param offs the model position
415
   * @return the model position of the end of the row containing the given
416
   * offset
417
   * @throws BadLocationException if the offset is invalid
418
   */
419
  public static final int getRowEnd(JTextComponent c, int offs)
420
      throws BadLocationException
421
  {
422
    String text = c.getText();
423
    if (text == null)
424
      return -1;
425
 
426
    // Do a binary search for the smallest position X > offs
427
    // such that that character at positino X is not on the same
428
    // line as the character at position offs
429
    int high = offs + ((text.length() - 1 - offs) / 2);
430
    int low = offs;
431
    int oldHigh = text.length() + 1;
432
    while (true)
433
      {
434
        if (c.modelToView(high).y != c.modelToView(offs).y)
435
          {
436
            oldHigh = high;
437
            high = low + ((high + 1 - low) / 2);
438
            if (oldHigh == high)
439
              return high - 1;
440
          }
441
        else
442
          {
443
            low = high;
444
            high += ((oldHigh - high) / 2);
445
            if (low == high)
446
              return low;
447
          }
448
      }
449
  }
450
 
451
  /**
452
   * Get the model position of the start of the row that contains the specified
453
   * model position. Return null if the given JTextComponent does not have a
454
   * size.
455
   *
456
   * @param c the JTextComponent
457
   * @param offs the model position
458
   * @return the model position of the start of the row containing the given
459
   *         offset
460
   * @throws BadLocationException if the offset is invalid
461
   */
462
  public static final int getRowStart(JTextComponent c, int offs)
463
      throws BadLocationException
464
  {
465
    String text = c.getText();
466
    if (text == null)
467
      return -1;
468
 
469
    // Do a binary search for the greatest position X < offs
470
    // such that the character at position X is not on the same
471
    // row as the character at position offs
472
    int high = offs;
473
    int low = 0;
474
    int oldLow = 0;
475
    while (true)
476
      {
477
        if (c.modelToView(low).y != c.modelToView(offs).y)
478
          {
479
            oldLow = low;
480
            low = high - ((high + 1 - low) / 2);
481
            if (oldLow == low)
482
              return low + 1;
483
          }
484
        else
485
          {
486
            high = low;
487
            low -= ((low - oldLow) / 2);
488
            if (low == high)
489
              return low;
490
          }
491
      }
492
  }
493
 
494
  /**
495
   * Determine where to break the text in the given Segment, attempting to find
496
   * a word boundary.
497
   * @param s the Segment that holds the text
498
   * @param metrics the font metrics used for calculating the break point
499
   * @param x0 starting view location representing the start of the text
500
   * @param x the target view location
501
   * @param e the TabExpander used for expanding tabs (if this is null tabs
502
   * are expanded to 1 space)
503
   * @param startOffset the offset in the Document of the start of the text
504
   * @return the offset at which we should break the text
505
   */
506
  public static final int getBreakLocation(Segment s, FontMetrics metrics,
507
                                           int x0, int x, TabExpander e,
508
                                           int startOffset)
509
  {
510
    int mark = Utilities.getTabbedTextOffset(s, metrics, x0, x, e, startOffset);
511
    BreakIterator breaker = BreakIterator.getWordInstance();
512
    breaker.setText(s.toString());
513
 
514
    // If mark is equal to the end of the string, just use that position
515
    if (mark == s.count)
516
      return mark;
517
 
518
    // Try to find a word boundary previous to the mark at which we 
519
    // can break the text
520
    int preceding = breaker.preceding(mark + 1);
521
 
522
    if (preceding != 0)
523
      return preceding;
524
    else
525
      // If preceding is 0 we couldn't find a suitable word-boundary so
526
      // just break it on the character boundary
527
      return mark;
528
  }
529
 
530
  /**
531
   * Returns the paragraph element in the text component <code>c</code> at
532
   * the specified location <code>offset</code>.
533
   *
534
   * @param c the text component
535
   * @param offset the offset of the paragraph element to return
536
   *
537
   * @return the paragraph element at <code>offset</code>
538
   */
539
  public static final Element getParagraphElement(JTextComponent c, int offset)
540
  {
541
    Document doc = c.getDocument();
542
    Element par = null;
543
    if (doc instanceof StyledDocument)
544
      {
545
        StyledDocument styledDoc = (StyledDocument) doc;
546
        par = styledDoc.getParagraphElement(offset);
547
      }
548
    else
549
      {
550
        Element root = c.getDocument().getDefaultRootElement();
551
        int parIndex = root.getElementIndex(offset);
552
        par = root.getElement(parIndex);
553
      }
554
    return par;
555
  }
556
 
557
  /**
558
   * Returns the document position that is closest above to the specified x
559
   * coordinate in the row containing <code>offset</code>.
560
   *
561
   * @param c the text component
562
   * @param offset the offset
563
   * @param x the x coordinate
564
   *
565
   * @return  the document position that is closest above to the specified x
566
   *          coordinate in the row containing <code>offset</code>
567
   *
568
   * @throws BadLocationException if <code>offset</code> is not a valid offset
569
   */
570
  public static final int getPositionAbove(JTextComponent c, int offset, int x)
571
    throws BadLocationException
572
  {
573
    View rootView = c.getUI().getRootView(c);
574
    Rectangle r = c.modelToView(offset);
575
    int offs = c.viewToModel(new Point(x, r.y));
576
    int pos = rootView.getNextVisualPositionFrom(c, offs,
577
                                                 Position.Bias.Forward,
578
                                                 SwingConstants.NORTH,
579
                                                 new Position.Bias[1]);
580
    return pos;
581
  }
582
 
583
  /**
584
   * Returns the document position that is closest below to the specified x
585
   * coordinate in the row containing <code>offset</code>.
586
   *
587
   * @param c the text component
588
   * @param offset the offset
589
   * @param x the x coordinate
590
   *
591
   * @return  the document position that is closest above to the specified x
592
   *          coordinate in the row containing <code>offset</code>
593
   *
594
   * @throws BadLocationException if <code>offset</code> is not a valid offset
595
   */
596
  public static final int getPositionBelow(JTextComponent c, int offset, int x)
597
    throws BadLocationException
598
  {
599
    View rootView = c.getUI().getRootView(c);
600
    Rectangle r = c.modelToView(offset);
601
    int offs = c.viewToModel(new Point(x, r.y));
602
    int pos = rootView.getNextVisualPositionFrom(c, offs,
603
                                                 Position.Bias.Forward,
604
                                                 SwingConstants.SOUTH,
605
                                                 new Position.Bias[1]);
606
    return pos;
607
  }
608
}

powered by: WebSVN 2.1.0

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