Statistics
| Revision:

root / import / ext3D / trunk / install-extension3d / IzPack / src / lib / com / izforge / izpack / util / MultiLineLabel.java @ 15280

History | View | Annotate | Download (24.8 KB)

1
/*
2
 * $Id: MultiLineLabel.java,v 1.1 2006/06/14 07:29:07 cesar Exp $
3
 * IzPack version
4
 * Copyright (C) 1997 - 2002 Elmar Grom
5
 *
6
 * File :               MultiLineLabel.java
7
 * Description :        A swing component to display static text that spans
8
 *                      multiple lines.
9
 * Author's email :     elmar@grom.net
10
 * Author's Website :   http://www.izforge.com
11
 *
12
 * This program is free software; you can redistribute it and/or
13
 * modify it under the terms of the GNU General Public License
14
 * as published by the Free Software Foundation; either version 2
15
 * of the License, or any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25
 */
26

    
27
package   com.izforge.izpack.util;
28

    
29
import java.awt.Color;
30
import java.awt.Dimension;
31
import java.awt.Font;
32
import java.awt.FontMetrics;
33
import java.awt.Graphics;
34
import java.util.Vector;
35

    
36
import javax.swing.JComponent;
37
  
38
/*---------------------------------------------------------------------------*/
39
/**
40
 * <BR>
41
 * <code>MultiLineLabel</code> may be used in place of javax.swing.JLabel.
42
 * <BR> <BR>
43
 * This class implements a component that is capable of displaying multiple
44
 * lines of text. Line breaks are inserted automatically whenever a line of
45
 * text extends beyond the predefined maximum line length. Line breaks will
46
 * only be inserted between words, except where a single word is longer than
47
 * the maximum line length. Line breaks may be forced at any location in the
48
 * text by inserting a newline (\n). White space that is not valuable (i.e. is
49
 * placed at the beginning of a new line or at the very beginning or end of 
50
 * the text) is removed.
51
 * <br><br>
52
 * <b>Note:</b> you can set the maximum width of the label either through one
53
 * of the constructors or you can call <code>setMaxWidth()</code> explicitly.
54
 * If this is not set, <code>MultiLineLabel</code> will derive its width from
55
 * the parent component.
56
 *
57
 * @version  0.0.1 / 05-15-97
58
 * @version  1.0   / 04-13-02
59
 * @author   Elmar Grom
60
 */
61
/*---------------------------------------------------------------------------*
62
 * Reviving some old code here that was written before there was swing.
63
 * The original was written to work with awt. I had to do some masaging to
64
 * make it a JComponent and I hope it behaves like a reasonably good mannered
65
 * swing component.
66
 *---------------------------------------------------------------------------*/
67
public class MultiLineLabel extends JComponent
68
{
69
    public  static final int LEFT           = 0;     // alignment constants
70
    public  static final int CENTER         = 1;
71
    public  static final int RIGHT          = 2;
72

    
73
    public  static final int DEFAULT_MARGIN = 10;
74
    public  static final int DEFAULT_ALIGN  = LEFT;
75
    public  static final int LEAST_ALLOWED  = 200;   // default setting for maxAllowed
76

    
77
    private static final int FOUND          = 0;     // constants for string search.
78
    private static final int NOT_FOUND      = 1;
79
    private static final int NOT_DONE       = 0;
80
    private static final int DONE           = 1;
81

    
82
    private static final char [] WHITE_SPACE = {' ','\n','\t'};
83
    private static final char [] SPACES      = {' ','\t'};
84
    private static final char    NEW_LINE    = '\n';
85

    
86
    protected Vector     line = new Vector ();// text lines to display
87

    
88
    protected String     labelText;          // text lines to display
89
    protected int        numLines;           // the number of lines
90
    protected int        marginHeight;       // top and bottom margins
91
    protected int        marginWidth;        // left and right margins
92
    protected int        lineHeight;         // total height of the font
93
    protected int        lineAscent;         // font height above the baseline
94
    protected int        lineDescent;        // font hight below the baseline
95
    protected int []     lineWidth;          // width of each line
96
    protected int        maxWidth;           // width of the widest line
97
    private   int        maxAllowed = LEAST_ALLOWED; // max width allowed to use
98
    private   boolean    maxAllowedSet  = false;  // signals if the max allowed width has been explicitly set
99

    
100
    protected int        alignment   = LEFT; // default text alignment
101

    
102

    
103
   /*-------------------------------------------------------------------*/
104
   /**
105
    * Constructor
106
    *
107
    * @param text          the text to be displayed
108
    * @param horMargin     the horizontal margin for the label
109
    * @param vertMargin    the vertical margin for the label
110
    * @param maxWidth      the maximum allowed width of the text
111
    * @param justify       the text alignment for the label
112
    */
113
   /*-------------------------------------------------------------------*
114
    * <detailed description / implementation details if applicable>
115
    *-------------------------------------------------------------------*/
116
    public MultiLineLabel  (String    text,
117
                            int       horMargin,
118
                            int       vertMargin,
119
                            int       maxWidth,
120
                            int       justify)
121
    {
122
      this.labelText      = text;
123
      this.marginWidth    = horMargin;
124
      this.marginHeight   = vertMargin;
125
      this.maxAllowed     = maxWidth;
126
      this.maxAllowedSet  = true;
127
      this.alignment      = justify;
128
    }
129
   /*-------------------------------------------------------------------*/
130
   /**
131
    * Constructor using default max-width and alignment.
132
    *
133
    * @param label         the text to be displayed
134
    * @param marginWidth   the horizontal margin for the label
135
    * @param marginHeight  the vertical margin for the label
136
    */
137
   /*-------------------------------------------------------------------*
138
    * <detailed description / implementation details if applicable>
139
    *-------------------------------------------------------------------*/
140
    public MultiLineLabel  (String    label,
141
                            int       marginWidth,
142
                            int       marginHeight)
143
    {
144
      this.labelText    = label;
145
      this.marginWidth  = marginWidth;
146
      this.marginHeight = marginHeight;
147
    }
148
   /*-------------------------------------------------------------------*/
149
   /**
150
    * Constructor using default max-width, and margin.
151
    *
152
    * @param label         the text to be displayed
153
    * @param alignment     the text alignment for the label
154
    */
155
   /*-------------------------------------------------------------------*
156
    * <detailed description / implementation details if applicable>
157
    *-------------------------------------------------------------------*/
158
    public MultiLineLabel  (String    label,
159
                            int       alignment)
160
    {
161
      this.labelText = label;
162
      this.alignment = alignment;
163
    }
164

    
165
   /*-------------------------------------------------------------------*/
166
   /**
167
    * Constructor using default max-width, alignment,
168
    * and margin.
169
    *
170
    * @param label         the text to be displayed
171
    */
172
   /*-------------------------------------------------------------------*
173
    * <detailed description / implementation details if applicable>
174
    *-------------------------------------------------------------------*/
175
    public MultiLineLabel  (String    label)
176
    {
177
      this.labelText = label;
178
    }
179
   /*-------------------------------------------------------------------*/
180
   /**
181
    * This method searches the target string for occurences of any of the
182
    * characters in the source string. The return value is the position of the
183
    * first hit. Based on the mode parameter the hit position is either the
184
    * position where any of the source characters first was found or the first
185
    * position where none of the source characters where found.
186
    *
187
    *
188
    * @return position of the first occurence
189
    * @param  target  the text to be searched
190
    * @param  start   the start position for the search
191
    * @param  source  the list of characters to be searched for
192
    * @param  mode    the search mode
193
    *                 FOUND     = reports first found
194
    *                 NOT_FOUND = reports first not found
195
    */
196
   /*-------------------------------------------------------------------*
197
    * <detailed description / implementation details if applicable>
198
    *-------------------------------------------------------------------*/
199
    int getPosition (String  target,
200
                     int     start,
201
                     char [] source,
202
                     int     mode)
203
    {
204
        int     status;
205
        int     position;
206
        int     scan;
207
        int     targetEnd;
208
        int     sourceLength;
209
        char    temp;
210

    
211
        targetEnd       = (target.length () - 1);
212
        sourceLength    = source.length;
213
        position        = start;
214

    
215
        if (mode == FOUND)
216
        {
217
            status = NOT_DONE;
218
            while (status != DONE)
219
            {
220
                position++;
221
                if (!(position < targetEnd)) // end of string reached, the next
222
                {                            // statement would cause a runtime error
223
                    return (targetEnd);
224
                }
225
                temp = target.charAt (position);
226
                for (scan = 0; scan < sourceLength; scan++) // walk through the source
227
                {                                           // string and compare each char
228
                    if (source [scan] == temp)
229
                    {
230
                        status = DONE;
231
                    }
232
                }
233
            }
234
            return (position);
235
        }
236
        else if (mode == NOT_FOUND)
237
        {
238
            status = NOT_DONE;
239
            while (status != DONE)
240
            {
241
                position++;
242
                if (!(position < targetEnd)) // end of string reached, the next
243
                {                            // statement would cause a runtime error
244
                    return (targetEnd);
245
                }
246
                temp    = target.charAt (position);
247
                status  = DONE;
248
                for (scan = 0; scan < sourceLength; scan++) // walk through the source
249
                {                                           // string and compare each char
250
                    if (source [scan] == temp)
251
                    {
252
                        status = NOT_DONE;
253
                    }
254
                }
255
            }
256
            return (position);
257
        }
258
        return (0);
259
    }
260
   /*-------------------------------------------------------------------*/
261
   /**
262
    * This method scans the input string until the max allowed width is reached.
263
    * The return value indicates the position just before this happens.
264
    *
265
    *
266
    * @return position  character position just before the string is too long
267
    * @param  word      word to break
268
    */
269
   /*-------------------------------------------------------------------*
270
    * <detailed description / implementation details if applicable>
271
    *-------------------------------------------------------------------*/
272
    int breakWord  (String      word,
273
                    FontMetrics fm)
274
    {
275
      int width;
276
      int currentPos;
277
      int endPos;
278

    
279
      width       = 0;
280
      currentPos  = 0;
281
      endPos      = word.length () - 1;
282

    
283
      // make sure we don't end up with a negative position
284
      if (endPos <= 0)
285
      {
286
        return (currentPos);
287
      }
288
      // seek the position where the word first is longer than allowed
289
      while ((width      < maxAllowed) &&
290
             (currentPos < endPos)             )
291
      {
292
        currentPos++;
293
        width      = fm.stringWidth (labelText.substring (0, currentPos));
294
      }
295
      // adjust to get the chatacter just before (this should make it a bit
296
      // shorter than allowed!)
297
      if (currentPos != endPos)
298
      {
299
        currentPos--;
300
      }
301
      return (currentPos);
302
    }
303
   /*-------------------------------------------------------------------*/
304
   /**
305
    * This method breaks the label text up into multiple lines of text.
306
    * Line breaks are established based on the maximum available space.
307
    * A new line is started whenever a line break is encountered, even
308
    * if the permissible length is not yet reached. Words are broken
309
    * only if a single word happens to be longer than one line.
310
    */
311
   /*-------------------------------------------------------------------*/
312
    private void divideLabel ()
313
    {
314
      int width;
315
      int startPos;
316
      int currentPos;
317
      int lastPos;
318
      int endPos;
319

    
320
      line.clear ();
321
      FontMetrics fm = this.getFontMetrics (this.getFont ());
322

    
323
      startPos    = 0;
324
      currentPos  = startPos;
325
      lastPos     = currentPos;
326
      endPos      = (labelText.length () - 1);
327

    
328
      while (currentPos < endPos)
329
      {
330
        width = 0;
331
        // ----------------------------------------------------------------
332
        // find the first substring that occupies more than the granted space.
333
        // Break at the end of the string or a line break
334
        // ----------------------------------------------------------------
335
        while (    (width                         <  maxAllowed)
336
                && (currentPos                    <  endPos)
337
                && (labelText.charAt (currentPos) != NEW_LINE))
338
        {
339
          lastPos    = currentPos;
340
          currentPos = getPosition (labelText, currentPos, WHITE_SPACE, FOUND);
341
          width      = fm.stringWidth (labelText.substring (startPos, currentPos));
342
        }
343
        // ----------------------------------------------------------------
344
        // if we have a line break we want to copy everything up to currentPos
345
        // ----------------------------------------------------------------
346
        if (labelText.charAt (currentPos) == NEW_LINE)
347
        {
348
          lastPos = currentPos;
349
        }
350
        // ----------------------------------------------------------------
351
        // if we are at the end of the string we want to copy everything up to
352
        // the last character. Since there seems to be a problem to get the last
353
        // character if the substring definition ends at the very last character
354
        // we have to call a different substring function than normal.
355
        // ----------------------------------------------------------------
356
        if (currentPos == endPos)
357
        {
358
          lastPos = currentPos;
359
          String s = labelText.substring (startPos);
360
          line.addElement (s);
361
        }
362
        // ----------------------------------------------------------------
363
        // in all other cases copy the substring that we have found to fit and
364
        // add it as a new line of text to the line vector.
365
        // ----------------------------------------------------------------
366
        else
367
        {
368
          // ------------------------------------------------------------
369
          // make sure it's not a single word. If so we must break it at the
370
          // proper location.
371
          // ------------------------------------------------------------
372
          if (lastPos == startPos)
373
          {
374
              lastPos = startPos +
375
                          breakWord (labelText.substring (startPos, currentPos), fm);
376
          }
377
          String s = labelText.substring (startPos, lastPos);
378
          line.addElement (s);
379
        }
380

    
381
        // ----------------------------------------------------------------
382
        // seek for the end of the white space to cut out any unnecessary spaces
383
        // and tabs and set the new start condition.
384
        // ----------------------------------------------------------------
385
        startPos    = getPosition (labelText, lastPos, SPACES, NOT_FOUND);
386
        currentPos  = startPos;
387
      }
388

    
389
      numLines      = line.size ();
390
      lineWidth     = new int [numLines];
391
    }
392
   /*-------------------------------------------------------------------*/
393
   /**
394
    * This method finds the font size, each line width and the widest line.
395
    *
396
    */
397
   /*-------------------------------------------------------------------*/
398
    protected void measure ()
399
    {
400
      if (!maxAllowedSet)
401
      {
402
        maxAllowed = getParent ().getSize ().width;
403
      }
404

    
405
      // return if width is too small
406
      if (maxAllowed < (20))
407
      {
408
        return;
409
      }
410

    
411
      FontMetrics fm  = this.getFontMetrics (this.getFont ());
412
      
413
      // return if no font metrics available
414
      if (fm == null)
415
      {
416
        return;
417
      }
418

    
419
      divideLabel ();
420

    
421
      this.lineHeight  = fm.getHeight  ();
422
      this.lineDescent = fm.getDescent ();
423
      this.maxWidth    = 0;
424

    
425
      for (int i = 0; i < numLines; i++)
426
      {
427
        this.lineWidth[i] = fm.stringWidth ((String)this.line.elementAt (i));
428
        if (this.lineWidth[i] > this.maxWidth)
429
        {
430
            this.maxWidth = this.lineWidth[i];
431
        }
432
      }
433
    }
434
   /*-------------------------------------------------------------------*/
435
   /**
436
    * This method draws the label.
437
    *
438
    * @param graphics  the device context
439
    */
440
   /*-------------------------------------------------------------------*/
441
    public void paint (Graphics graphics)
442
    {
443
        int x;
444
        int y;
445

    
446
        measure ();
447
        Dimension d = this.getSize ();
448

    
449
        y = lineAscent + (d.height - (numLines * lineHeight)) / 2;
450

    
451
        for (int i = 0; i < numLines; i++)
452
        {
453
            y += lineHeight;
454
            switch (alignment)
455
            {
456
                case LEFT   : x = marginWidth;
457
                              break;
458
                case CENTER : x = (d.width - lineWidth[i]) / 2;
459
                              break;
460
                case RIGHT  : x = d.width - marginWidth - lineWidth[i];
461
                              break;
462
                default     : x = (d.width - lineWidth[i]) / 2;
463
            }
464
            graphics.drawString ((String)line.elementAt (i), x, y);
465
        }
466
    }
467

    
468
   /*-------------------------------------------------------------------*/
469
   /**
470
    * This method may be used to set the label text
471
    *
472
    * @param labelText the text to be displayed
473
    */
474
   /*-------------------------------------------------------------------*/
475
    public void setText (String labelText)
476
    {
477
      this.labelText = labelText;
478
      repaint ();
479
    }
480
   /*-------------------------------------------------------------------*/
481
   /**
482
    * This method may be used to set the font that should be used to draw the
483
    * label
484
    *
485
    * @param font  font to be used within the label
486
    */
487
   /*-------------------------------------------------------------------*/
488
    public void setFont (Font font)
489
    {
490
      super.setFont (font);
491
      repaint ();
492
    }
493
   /*-------------------------------------------------------------------*/
494
   /**
495
    * This method may be used to set the color in which the text should be drawn
496
    *
497
    * @param color  the text color
498
    */
499
   /*-------------------------------------------------------------------*/
500
    public void setColor (Color color)
501
    {
502
      super.setForeground (color);
503
      repaint ();
504
    }
505
   /*-------------------------------------------------------------------*/
506
   /**
507
    * This method may be used to set the text alignment for the label
508
    *
509
    * @param alignment  the alignment, possible values are LEFT, CENTER, RIGHT
510
    */
511
   /*-------------------------------------------------------------------*/
512
    public void setJustify (int alignment)
513
    {
514
      this.alignment = alignment;
515
      repaint ();
516
    }
517
   /*-------------------------------------------------------------------*/
518
   /**
519
    * This method may be used to set the max allowed line width
520
    *
521
    * @param width  the max allowed line width in pixels
522
    */
523
   /*-------------------------------------------------------------------*/
524
    public void setMaxWidth (int width)
525
    {
526
      this.maxAllowed     = width;
527
      this.maxAllowedSet  = true;
528
      repaint ();
529
    }
530
   /*-------------------------------------------------------------------*/
531
   /**
532
    * This method may be used to set the horizontal margin
533
    *
534
    * @param margin  the margin to the left and to the right of the label
535
    */
536
   /*-------------------------------------------------------------------*/
537
    public void setMarginWidth (int margin)
538
    {
539
      this.marginWidth = margin;
540
      repaint ();
541
    }
542
   /*-------------------------------------------------------------------*/
543
   /**
544
    * This method may be used to set the vertical margin for the label
545
    *
546
    * @param margin  the margin on the top and bottom of the label
547
    */
548
   /*-------------------------------------------------------------------*/
549
    public void setMarginHeight (int margin)
550
    {
551
      this.marginHeight = margin;
552
      repaint ();
553
    }
554
   /*-------------------------------------------------------------------*/
555
   /**
556
    * Moves and resizes this component. The new location of the top-left
557
    * corner is specified by <code>x</code> and <code>y</code>, and the
558
    * new size is specified by <code>width</code> and <code>height</code>.
559
    *
560
    * @param     x      The new x-coordinate of this component.
561
    * @param     y      The new y-coordinate of this component.
562
    * @param     width  The new width of this component.
563
    * @param     height The new height of this component.
564
    */
565
   /*-------------------------------------------------------------------*/
566
    public void setBounds (int x, int y, int width, int height)
567
    {
568
      super.setBounds (x, y, width, height);
569
      this.maxAllowed     = width;
570
      this.maxAllowedSet  = true;
571
    }
572
   /*-------------------------------------------------------------------*/
573
   /**
574
    * This method may be used to retrieve the text alignment for the label
575
    *
576
    * @return alignment  the text alignment currently in use for the label
577
    */
578
   /*-------------------------------------------------------------------*/
579
    public int getAlignment ()
580
    {
581
      return (this.alignment);
582
    }
583

    
584
   /*-------------------------------------------------------------------*/
585
   /**
586
    * This method may be used to retrieve the horizontal margin for the label
587
    *
588
    * @return marginWidth  the margin currently in use to the left and right of
589
    *                      the label
590
    */
591
   /*-------------------------------------------------------------------*/
592
    public int getMarginWidth ()
593
    {
594
      return (this.marginWidth);
595
    }
596
   /*-------------------------------------------------------------------*/
597
   /**
598
    * This method may be used to retrieve the vertical margin for the label
599
    *
600
    * @return marginHeight  the margin currently in use on the top and bottom of
601
    *                       the label
602
    */
603
   /*-------------------------------------------------------------------*/
604
    public int getMarginHeight ()
605
    {
606
      return (this.marginHeight);
607
    }
608

    
609
   /*-------------------------------------------------------------------*/
610
   /**
611
    * This method is typically used by the layout manager, it reports the
612
    * necessary space to display the label comfortably.
613
    */
614
   /*-------------------------------------------------------------------*/
615
    public Dimension getPreferredSize ()
616
    {
617
      measure ();
618
      return (new Dimension (maxAllowed,
619
                 (numLines * (lineHeight + lineAscent + lineDescent)) + (2 * marginHeight)));
620
    }
621
   /*-------------------------------------------------------------------*/
622
   /**
623
    * This method is typically used by the layout manager, it reports the
624
    * absolute minimum space required to display the entire label.
625
    *
626
    */
627
   /*-------------------------------------------------------------------*/
628
    public Dimension getMinimumSize ()
629
    {
630
      measure ();
631
      return (new Dimension (maxAllowed,
632
                 (numLines * (lineHeight + lineAscent + lineDescent)) + (2 * marginHeight)));
633
    }
634
   /*-------------------------------------------------------------------*/
635
   /**
636
    * This method is called by the system after this object is first created.
637
    *
638
    */
639
   /*-------------------------------------------------------------------*/
640
    public void addNotify ()
641
    {
642
      super.addNotify ();                 // invoke the superclass
643
    }
644
}
645
/*---------------------------------------------------------------------------*/