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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* BasicBorders.java --
2
   Copyright (C) 2003, 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.plaf.basic;
40
 
41
import java.awt.Color;
42
import java.awt.Component;
43
import java.awt.Graphics;
44
import java.awt.Insets;
45
import java.awt.Rectangle;
46
import java.io.Serializable;
47
 
48
import javax.swing.AbstractButton;
49
import javax.swing.ButtonModel;
50
import javax.swing.JButton;
51
import javax.swing.JPopupMenu;
52
import javax.swing.JSplitPane;
53
import javax.swing.JToolBar;
54
import javax.swing.UIManager;
55
import javax.swing.border.AbstractBorder;
56
import javax.swing.border.BevelBorder;
57
import javax.swing.border.Border;
58
import javax.swing.plaf.BorderUIResource;
59
import javax.swing.plaf.UIResource;
60
import javax.swing.text.JTextComponent;
61
 
62
/**
63
 * Provides various borders for the Basic look and feel.
64
 *
65
 * @author Sascha Brawer (brawer@dandelis.ch)
66
 */
67
public class BasicBorders
68
{
69
  /**
70
   * A MarginBorder that gets shared by multiple components.
71
   * Created on demand by the private helper function {@link
72
   * #getMarginBorder()}.
73
   */
74
  private static MarginBorder sharedMarginBorder;
75
 
76
 
77
  /**
78
   * Returns a border for drawing push buttons.
79
   *
80
   * <p>The colors of the border are retrieved from the
81
   * <code>UIDefaults</code> of the currently active look and feel
82
   * using the keys <code>&#x201c;Button.shadow&#x201d;</code>,
83
   * <code>&#x201c;Button.darkShadow&#x201d;</code>,
84
   * <code>&#x201c;Button.light&#x201d;</code>, and
85
   * <code>&#x201c;Button.highlight&#x201d;</code>.
86
   *
87
   * <p><img src="doc-files/BasicBorders.ButtonBorder-1.png" width="300"
88
   * height="170" alt="[A screen shot of the returned border]" />
89
   *
90
   * @return a {@link
91
   *         javax.swing.plaf.BorderUIResource.CompoundBorderUIResource}
92
   *         whose outer border is a {@link ButtonBorder} and whose
93
   *         inner border is a {@link MarginBorder}.
94
   */
95
  public static Border getButtonBorder()
96
  {
97
    Border outer;
98
 
99
    /* The keys for UIDefaults have been determined by writing a
100
     * test program that dumps the UIDefaults to stdout; that program
101
     * was run on a JDK 1.4.1_01 for GNU/Linux. Note that in the API,
102
     * the key "light" is usually called "highlight", and "highlight"
103
     * is usually called "lightHighlight".
104
     */
105
    outer = new ButtonBorder(UIManager.getColor("Button.shadow"),
106
                             UIManager.getColor("Button.darkShadow"),
107
                             UIManager.getColor("Button.light"),
108
                             UIManager.getColor("Button.highlight"));
109
 
110
    /* While the inner border is shared between multiple buttons,
111
     * we do not share the outer border because ButtonBorders store
112
     * their border colors. We cannot guarantee that the colors
113
     * (which come from UIDefaults) are unchanged between invocations
114
     * of getButtonBorder. We could store the last colors, and share
115
     * the button border if the colors are the same as in the last
116
     * invocation, but it probably is not worth the effort.
117
     */
118
    return new BorderUIResource.CompoundBorderUIResource(
119
      outer,
120
      /* inner */ getMarginBorder());
121
  }
122
 
123
 
124
  /**
125
   * Returns a border for drawing radio buttons.
126
   *
127
   * <p>The colors of the border are retrieved from the
128
   * <code>UIDefaults</code> of the currently active look and feel
129
   * using the keys <code>&#x201c;RadioButton.shadow&#x201d;</code>,
130
   * <code>&#x201c;RadioButton.darkShadow&#x201d;</code>,
131
   * <code>&#x201c;RadioButton.light&#x201d;</code>, and
132
   * <code>&#x201c;RadioButton.highlight&#x201d;</code>.
133
   *
134
   * <p><img src="doc-files/BasicBorders.RadioButtonBorder-1.png" width="300"
135
   * height="135" alt="[A screen shot of the returned border]" />
136
   *
137
   * @return a {@link
138
   *         javax.swing.plaf.BorderUIResource.CompoundBorderUIResource}
139
   *         whose outer border is a {@link RadioButtonBorder} and whose
140
   *         inner border is a {@link MarginBorder}.
141
   */
142
  public static Border getRadioButtonBorder()
143
  {
144
    Border outer;
145
 
146
    /* The keys for UIDefaults have been determined by writing a
147
     * test program that dumps the UIDefaults to stdout; that program
148
     * was run on a JDK 1.4.1_01 for GNU/Linux. Note that in the API,
149
     * the key "light" is usually called "highlight", and "highlight"
150
     * is usually called "lightHighlight".
151
     */
152
    outer = new RadioButtonBorder(
153
      UIManager.getColor("RadioButton.shadow"),
154
      UIManager.getColor("RadioButton.darkShadow"),
155
      UIManager.getColor("RadioButton.light"),
156
      UIManager.getColor("RadioButton.highlight"));
157
 
158
    /* While the inner border is shared between multiple buttons, we
159
     * do not share the outer border because RadioButtonBorders, being
160
     * ButtonBorders, store their border colors. We cannot guarantee
161
     * that the colors (which come from UIDefaults) are unchanged
162
     * between invocations of getButtonBorder. We could store the last
163
     * colors, and share the button border if the colors are the same
164
     * as in the last invocation, but it probably is not worth the
165
     * effort.
166
     */
167
    return new BorderUIResource.CompoundBorderUIResource(
168
      outer,
169
      /* inner */ getMarginBorder());
170
  }
171
 
172
 
173
  /**
174
   * Returns a border for drawing toggle buttons.
175
   *
176
   * <p>The colors of the border are retrieved from the
177
   * <code>UIDefaults</code> of the currently active look and feel
178
   * using the keys <code>&#x201c;ToggleButton.shadow&#x201d;</code>,
179
   * <code>&#x201c;ToggleButton.darkShadow&#x201d;</code>,
180
   * <code>&#x201c;ToggleButton.light&#x201d;</code>, and
181
   * <code>&#x201c;ToggleButton.highlight&#x201d;</code>.
182
   *
183
   * <p><img src="doc-files/BasicBorders.ToggleButtonBorder-1.png" width="270"
184
   * height="135" alt="[A screen shot of the returned border]" />
185
   *
186
   * @return a {@link
187
   *         javax.swing.plaf.BorderUIResource.CompoundBorderUIResource}
188
   *         whose outer border is a {@link ToggleButtonBorder} and whose
189
   *         inner border is a {@link MarginBorder}.
190
   */
191
  public static Border getToggleButtonBorder()
192
  {
193
    Border outer;
194
 
195
    /* The keys for UIDefaults have been determined by writing a
196
     * test program that dumps the UIDefaults to stdout; that program
197
     * was run on a JDK 1.4.1_01 for GNU/Linux. Note that in the API,
198
     * the key "light" is usually called "highlight", and "highlight"
199
     * is usually called "lightHighlight".
200
     */
201
    outer = new ToggleButtonBorder(
202
      UIManager.getColor("ToggleButton.shadow"),
203
      UIManager.getColor("ToggleButton.darkShadow"),
204
      UIManager.getColor("ToggleButton.light"),
205
      UIManager.getColor("ToggleButton.highlight"));
206
 
207
    /* While the inner border is shared between multiple buttons, we
208
     * do not share the outer border because ToggleButtonBorders, being
209
     * ButtonBorders, store their border colors. We cannot guarantee
210
     * that the colors (which come from UIDefaults) are unchanged
211
     * between invocations of getButtonBorder. We could store the last
212
     * colors, and share the button border if the colors are the same
213
     * as in the last invocation, but it probably is not worth the
214
     * effort.
215
     */
216
    return new BorderUIResource.CompoundBorderUIResource(
217
      outer,
218
      /* inner */ getMarginBorder());
219
  }
220
 
221
 
222
  /**
223
   * Returns a border for drawing a two-pixel thick separator line
224
   * below menu bars.
225
   *
226
   * <p>The colors of the border are retrieved from the
227
   * <code>UIDefaults</code> of the currently active look and feel
228
   * using the keys <code>&#x201c;MenuBar.shadow&#x201d;</code> and
229
   * <code>&#x201c;MenuBar.highlight&#x201d;</code>.
230
   *
231
   * <p><img src="doc-files/BasicBorders.MenuBarBorder-1.png" width="500"
232
   * height="140" alt="[A screen shot of a JMenuBar with this border]" />
233
   *
234
   * @return a {@link MenuBarBorder}.
235
   *
236
   * @see javax.swing.JMenuBar
237
   */
238
  public static Border getMenuBarBorder()
239
  {
240
    /* See comment in methods above for why this border is not shared. */
241
    return new MenuBarBorder(UIManager.getColor("MenuBar.shadow"),
242
                             UIManager.getColor("MenuBar.highlight"));
243
  }
244
 
245
 
246
  /**
247
   * Returns a border for drawing a one-pixel thick border around
248
   * split panes that are interrupted where the divider joins the
249
   * border.
250
   *
251
   * <p>The colors of the border are retrieved from the
252
   * <code>UIDefaults</code> of the currently active look and feel
253
   * using the keys <code>&#x201c;SplitPane.darkShadow&#x201d;</code> and
254
   * <code>&#x201c;SplitPane.highlight&#x201d;</code>.
255
   *
256
   * <p><img src="doc-files/BasicBorders.SplitPaneBorder-1.png" width="520"
257
   * height="200" alt="[A screen shot for JSplitPane.HORIZONTAL_SPLIT]" />
258
   *
259
   * <p><img src="doc-files/BasicBorders.SplitPaneBorder-2.png" width="520"
260
   * height="200" alt="[A screen shot for JSplitPane.VERTICAL_SPLIT]" />
261
   *
262
   * @return a {@link SplitPaneBorder}.
263
   *
264
   * @see javax.swing.JSplitPane
265
   * @see #getSplitPaneDividerBorder()
266
   */
267
  public static Border getSplitPaneBorder()
268
  {
269
    /* See comment in methods above for why this border is not shared. */
270
    return new SplitPaneBorder(UIManager.getColor("SplitPane.highlight"),
271
                               UIManager.getColor("SplitPane.darkShadow"));
272
  }
273
 
274
 
275
  /**
276
   * Returns a border for drawing a one-pixel thick border around
277
   * the divider of split panes.
278
   *
279
   * <p>The colors of the edges that are adjacent to the child components
280
   * of the <code>JSplitPane</code> are retrieved from the
281
   * <code>UIDefaults</code> of the currently active look and feel
282
   * using the keys <code>&#x201c;SplitPane.darkShadow&#x201d;</code> and
283
   * <code>&#x201c;SplitPane.highlight&#x201d;</code>. The color of the
284
   * other two edges is the background color of the divider.
285
   *
286
   * <p><img src="doc-files/BasicBorders.SplitPaneDividerBorder-1.png"
287
   * width="520" height="200" alt=
288
   * "[A screen shot for JSplitPane.HORIZONTAL_SPLIT]" />
289
   *
290
   * @return an instance of <code>SplitPaneDividerBorder</code>, which is
291
   *         not a public API class of this package.
292
   *
293
   * @see javax.swing.JSplitPane
294
   * @see javax.swing.plaf.basic.BasicSplitPaneDivider
295
   * @see #getSplitPaneBorder()
296
   *
297
   * @since 1.3
298
   */
299
  public static Border getSplitPaneDividerBorder()
300
  {
301
    /* See comment in methods above for why this border is not shared. */
302
    return new SplitPaneDividerBorder(
303
      UIManager.getColor("SplitPane.highlight"),
304
      UIManager.getColor("SplitPane.darkShadow"));
305
  }
306
 
307
 
308
  /**
309
   * Returns a border for drawing a border around a text field
310
   * that makes the field appear as etched into the surface.
311
   *
312
   * <p>The colors of the border are retrieved from the
313
   * <code>UIDefaults</code> of the currently active look and feel
314
   * using the keys <code>&#x201c;TextField.shadow&#x201d;</code>,
315
   * <code>&#x201c;TextField.darkShadow&#x201d;</code>,
316
   * <code>&#x201c;TextField.light&#x201d;</code>, and
317
   * <code>&#x201c;TextField.highlight&#x201d;</code>.
318
   *
319
   * <p><img src="doc-files/BasicBorders.FieldBorder-1.png" width="500"
320
   * height="200" alt="[A screen shot of a border returned by
321
   * this method]" />
322
   *
323
   * @return an instance of {@link FieldBorder}.
324
   *
325
   * @see javax.swing.JTextField
326
   * @see javax.swing.text.JTextComponent
327
   */
328
  public static Border getTextFieldBorder()
329
  {
330
    /* See comment in methods above for why this border is not shared. */
331
    return new FieldBorder(
332
      UIManager.getColor("TextField.shadow"),
333
      UIManager.getColor("TextField.darkShadow"),
334
      UIManager.getColor("TextField.light"),
335
      UIManager.getColor("TextField.highlight"));
336
  }
337
 
338
 
339
  /**
340
   * Returns a two-pixel thick, green
341
   * <code>LineBorderUIResource</code>.  This is so ugly that look and
342
   * feels better use different borders for their progress bars, or
343
   * they will look really terrible.
344
   *
345
   * <p><img src="doc-files/BasicBorders-1.png" width="120" height="80"
346
   * alt="[A screen shot of a border returned by this method]" />
347
   */
348
  public static Border getProgressBarBorder()
349
  {
350
    /* There does not seem to exist a way to parametrize the color
351
     * or thickness of the border through UIDefaults.
352
     */
353
    return new BorderUIResource.LineBorderUIResource(Color.green, 2);
354
  }
355
 
356
 
357
  /**
358
   * Returns a border that is composed of a raised bevel border and a
359
   * one-pixel thick line border.
360
   *
361
   * <p><img src="doc-files/BasicBorders-2.png" width="300" height="200"
362
   * alt="[A screen shot of a border returned by this method]" />
363
   *
364
   * <p>The colors of the border are retrieved from the
365
   * <code>UIDefaults</code> of the currently active look and feel
366
   * using the keys <code>&#x201c;InternalFrame.borderShadow&#x201d;</code>,
367
   * <code>&#x201c;InternalFrame.borderDarkShadow&#x201d;</code>,
368
   * <code>&#x201c;InternalFrame.borderLight&#x201d;</code>,
369
   * <code>&#x201c;InternalFrame.borderHighlight&#x201d;</code>, and
370
   * (for the inner one-pixel thick line)
371
   * <code>&#x201c;InternalFrame.borderColor&#x201d;</code>.
372
   */
373
  public static Border getInternalFrameBorder()
374
  {
375
    Color shadow, darkShadow, highlight, lightHighlight, line;
376
 
377
    /* See comment in methods above for why this border is not shared. */
378
    shadow = UIManager.getColor("InternalFrame.borderShadow");
379
    darkShadow = UIManager.getColor("InternalFrame.borderDarkShadow");
380
    highlight = UIManager.getColor("InternalFrame.borderLight");
381
    lightHighlight = UIManager.getColor("InternalFrame.borderHighlight");
382
    line = UIManager.getColor("InternalFrame.borderColor");
383
 
384
    return new BorderUIResource.CompoundBorderUIResource(
385
      /* outer border */
386
      new BorderUIResource.BevelBorderUIResource(
387
        BevelBorder.RAISED,
388
        (highlight != null) ? highlight : Color.lightGray,
389
        (lightHighlight != null) ? lightHighlight : Color.white,
390
        (darkShadow != null) ? darkShadow : Color.black,
391
        (shadow != null) ? shadow : Color.gray),
392
 
393
      /* inner border */
394
      new BorderUIResource.LineBorderUIResource(
395
        (line != null) ? line : Color.lightGray));
396
  }
397
 
398
 
399
  /**
400
   * Returns a shared MarginBorder.
401
   */
402
  static Border getMarginBorder()  // intentionally not public
403
  {
404
    /* Swing is not designed to be thread-safe, so there is no
405
     * need to synchronize the access to the global variable.
406
     */
407
    if (sharedMarginBorder == null)
408
      sharedMarginBorder = new MarginBorder();
409
 
410
    return sharedMarginBorder;
411
  }
412
 
413
 
414
  /**
415
   * A border whose appearance depends on the state of
416
   * the enclosed button.
417
   *
418
   * <p><img src="doc-files/BasicBorders.ButtonBorder-1.png" width="300"
419
   * height="170" alt="[A screen shot of this border]" />
420
   *
421
   * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel
422
   *
423
   * @author Sascha Brawer (brawer@dandelis.ch)
424
   */
425
  public static class ButtonBorder
426
    extends AbstractBorder
427
    implements Serializable, UIResource
428
  {
429
    /**
430
     * Determined using the <code>serialver</code> tool
431
     * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
432
     */
433
    static final long serialVersionUID = -157053874580739687L;
434
 
435
 
436
    /**
437
     * The color for drawing the shaded parts of the border.
438
     * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel
439
     */
440
    protected Color shadow;
441
 
442
 
443
    /**
444
     * The color for drawing the dark shaded parts of the border.
445
     * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel
446
     */
447
    protected Color darkShadow;
448
 
449
 
450
    /**
451
     * The color for drawing the highlighted parts of the border.
452
     * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel
453
     */
454
    protected Color highlight;
455
 
456
 
457
    /**
458
     * The color for drawing the bright highlighted parts of the border.
459
     * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel
460
     */
461
    protected Color lightHighlight;
462
 
463
 
464
    /**
465
     * Constructs a new border for drawing a button in the Basic
466
     * look and feel.
467
     *
468
     * @param shadow the shadow color.
469
     * @param darkShadow a darker variant of the shadow color.
470
     * @param highlight the highlight color.
471
     * @param lightHighlight a brighter variant of the highlight  color.
472
     */
473
    public ButtonBorder(Color shadow, Color darkShadow,
474
                        Color highlight, Color lightHighlight)
475
    {
476
      /* These colors usually come from the UIDefaults of the current
477
       * look and feel. Use fallback values if the colors are not
478
       * supplied.  The API specification is silent about what
479
       * behavior is expected for null colors, so users should not
480
       * rely on this fallback (which is why it is not documented in
481
       * the above Javadoc).
482
       */
483
      this.shadow = (shadow != null) ? shadow : Color.gray;
484
      this.darkShadow = (darkShadow != null) ? darkShadow : Color.black;
485
      this.highlight = (highlight != null) ? highlight : Color.lightGray;
486
      this.lightHighlight = (lightHighlight != null)
487
        ? lightHighlight
488
        : Color.white;
489
    }
490
 
491
 
492
    /**
493
     * Paints the ButtonBorder around a given component.
494
     *
495
     * @param c the component whose border is to be painted.
496
     * @param g the graphics for painting.
497
     * @param x the horizontal position for painting the border.
498
     * @param y the vertical position for painting the border.
499
     * @param width the width of the available area for painting the border.
500
     * @param height the height of the available area for painting the border.
501
     *
502
     * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel
503
     */
504
    public void paintBorder(Component c, Graphics  g,
505
                            int x, int y, int width, int height)
506
    {
507
      ButtonModel bmodel = null;
508
 
509
      if (c instanceof AbstractButton)
510
        bmodel = ((AbstractButton) c).getModel();
511
 
512
      BasicGraphicsUtils.drawBezel(
513
        g, x, y, width, height,
514
        /* pressed */ (bmodel != null)
515
                        && /* mouse button pressed */ bmodel.isPressed()
516
                        && /* mouse inside */ bmodel.isArmed(),
517
        /* default */ (c instanceof JButton)
518
                        && ((JButton) c).isDefaultButton(),
519
        shadow, darkShadow, highlight, lightHighlight);
520
    }
521
 
522
 
523
    /**
524
     * Measures the width of this border.
525
     *
526
     * <p>Although the thickness of the actually painted border
527
     * depends on the state of the enclosed component, this
528
     * measurement always returns the same amount of pixels.  Indeed,
529
     * it would be rather confusing if a button was appearing to
530
     * change its size depending on whether it is pressed or not.
531
     *
532
     * @param c the component whose border is to be measured.
533
     *
534
     * @return an Insets object whose <code>left</code>,
535
     *         <code>right</code>, <code>top</code> and
536
     *         <code>bottom</code> fields indicate the width of the
537
     *         border at the respective edge.
538
     *
539
     * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
540
     */
541
    public Insets getBorderInsets(Component c)
542
    {
543
      /* There is no obvious reason for overriding this method, but we
544
       * try to have exactly the same API as the Sun reference
545
       * implementation.
546
       */
547
      return getBorderInsets(c, null);
548
    }
549
 
550
 
551
    /**
552
     * Measures the width of this border, storing the results into a
553
     * pre-existing Insets object.
554
     *
555
     * <p>Although the thickness of the actually painted border
556
     * depends on the state of the enclosed component, this
557
     * measurement always returns the same amount of pixels.  Indeed,
558
     * it would be rather confusing if a button was appearing to
559
     * change its size depending on whether it is pressed or not.
560
     *
561
     * @param insets an Insets object for holding the result values.
562
     *        After invoking this method, the <code>left</code>,
563
     *        <code>right</code>, <code>top</code> and
564
     *        <code>bottom</code> fields indicate the width of the
565
     *        border at the respective edge.
566
     *
567
     * @return the same object that was passed for <code>insets</code>.
568
     *
569
     * @see #getBorderInsets(Component)
570
     */
571
    public Insets getBorderInsets(Component c, Insets insets)
572
    {
573
      /* The exact amount has been determined using a test program
574
       * that was run on the Sun reference implementation. With
575
       * Apple/Sun JDK 1.3.1 on MacOS X 10.1.5, the result is
576
       * [3, 3, 3, 3]. With Sun JDK 1.4.1_01 on Linux/x86, the
577
       * result is [2, 3, 3, 3]. We use the values from the 1.4.1_01
578
       * release.
579
       */
580
      if (insets == null)
581
        return new Insets(2, 3, 3, 3);
582
 
583
      insets.top = 2;
584
      insets.bottom = insets.left = insets.right = 3;
585
      return insets;
586
    }
587
  }
588
 
589
 
590
  /**
591
   * A border that makes its enclosed component appear as lowered
592
   * into the surface. Typically used for text fields.
593
   *
594
   * <p><img src="doc-files/BasicBorders.FieldBorder-1.png" width="500"
595
   * height="200" alt="[A screen shot of this border]" />
596
   *
597
   * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawEtchedRect
598
   *
599
   * @author Sascha Brawer (brawer@dandelis.ch)
600
   */
601
  public static class FieldBorder
602
    extends AbstractBorder
603
    implements UIResource
604
  {
605
    /**
606
     * Determined using the <code>serialver</code> tool
607
     * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
608
     */
609
    static final long serialVersionUID = 949220756998454908L;
610
 
611
 
612
    /**
613
     * The color for drawing the outer half of the top and left
614
     * edges.
615
     */
616
    protected Color shadow;
617
 
618
 
619
    /**
620
     * The color for drawing the inner half of the top and left
621
     * edges.
622
     */
623
    protected Color darkShadow;
624
 
625
 
626
    /**
627
     * The color for drawing the inner half of the bottom and right
628
     * edges.
629
     */
630
    protected Color highlight;
631
 
632
 
633
    /**
634
     * The color for drawing the outer half of the bottom and right
635
     * edges.
636
     */
637
    protected Color lightHighlight;
638
 
639
 
640
    /**
641
     * Constructs a new border for drawing a text field in the Basic
642
     * look and feel.
643
     *
644
     * @param shadow the color for drawing the outer half
645
     *        of the top and left edges.
646
     *
647
     * @param darkShadow the color for drawing the inner half
648
     *        of the top and left edges.
649
     *
650
     * @param highlight the color for drawing the inner half
651
     *        of the bottom and right edges.
652
     *
653
     * @param lightHighlight the color for drawing the outer half
654
     *        of the bottom and right edges.
655
     */
656
    public FieldBorder(Color shadow, Color darkShadow,
657
                       Color highlight, Color lightHighlight)
658
    {
659
      /* These colors usually come from the UIDefaults of the current
660
       * look and feel. Use fallback values if the colors are not
661
       * supplied.  The API specification is silent about what
662
       * behavior is expected for null colors, so users should not
663
       * rely on this fallback (which is why it is not documented in
664
       * the above Javadoc).
665
       */
666
      this.shadow = (shadow != null) ? shadow : Color.gray;
667
      this.darkShadow = (darkShadow != null) ? darkShadow : Color.black;
668
      this.highlight = (highlight != null) ? highlight : Color.lightGray;
669
      this.lightHighlight = (lightHighlight != null)
670
        ? lightHighlight : Color.white;
671
    }
672
 
673
 
674
    /**
675
     * Paints the FieldBorder around a given component.
676
     *
677
     * @param c the component whose border is to be painted.
678
     * @param g the graphics for painting.
679
     * @param x the horizontal position for painting the border.
680
     * @param y the vertical position for painting the border.
681
     * @param width the width of the available area for painting the border.
682
     * @param height the height of the available area for painting the border.
683
     *
684
     * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawEtchedRect
685
     */
686
    public void paintBorder(Component c, Graphics  g,
687
                            int x, int y, int width, int height)
688
    {
689
      BasicGraphicsUtils.drawEtchedRect(g, x, y, width, height,
690
                                        shadow, darkShadow,
691
                                        highlight, lightHighlight);
692
    }
693
 
694
 
695
    /**
696
     * Measures the width of this border.
697
     *
698
     * @param c the component whose border is to be measured.
699
     *        If <code>c</code> is an instance of {@link
700
     *        javax.swing.text.JTextComponent}, its margin is
701
     *        added to the border size.
702
     *
703
     * @return an Insets object whose <code>left</code>,
704
     *         <code>right</code>, <code>top</code> and
705
     *         <code>bottom</code> fields indicate the width of the
706
     *         border at the respective edge.
707
     *
708
     * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
709
     */
710
    public Insets getBorderInsets(Component c)
711
    {
712
      return getBorderInsets(c, null);
713
    }
714
 
715
 
716
    /**
717
     * Measures the width of this border, storing the results into a
718
     * pre-existing Insets object.
719
     *
720
     * @param c the component whose border is to be measured.
721
     *        If <code>c</code> is an instance of {@link
722
     *        javax.swing.text.JTextComponent}, its margin is
723
     *        added to the border size.
724
     *
725
     * @param insets an Insets object for holding the result values.
726
     *        After invoking this method, the <code>left</code>,
727
     *        <code>right</code>, <code>top</code> and
728
     *        <code>bottom</code> fields indicate the width of the
729
     *        border at the respective edge.
730
     *
731
     * @return the same object that was passed for <code>insets</code>.
732
     *
733
     * @see #getBorderInsets(Component)
734
     */
735
    public Insets getBorderInsets(Component c, Insets insets)
736
    {
737
      if (insets == null)
738
        insets = new Insets(2, 2, 2, 2);
739
      else
740
        insets.top = insets.left = insets.bottom = insets.right = 2;
741
 
742
      if (c instanceof JTextComponent)
743
      {
744
        Insets margin = ((JTextComponent) c).getMargin();
745
        insets.top += margin.top;
746
        insets.left += margin.left;
747
        insets.bottom += margin.bottom;
748
        insets.right += margin.right;
749
      }
750
 
751
      return insets;
752
    }
753
  }
754
 
755
 
756
  /**
757
   * An invisible, but spacing border whose margin is determined
758
   * by calling the <code>getMargin()</code> method of the enclosed
759
   * component.  If the enclosed component has no such method,
760
   * this border will not occupy any space.
761
   *
762
   * <p><img src="doc-files/BasicBorders.MarginBorder-1.png" width="325"
763
   * height="200" alt="[An illustration that shows how MarginBorder
764
   * determines its borders]" />
765
   *
766
   * @author Sascha Brawer (brawer@dandelis.ch)
767
   */
768
  public static class MarginBorder
769
    extends AbstractBorder
770
    implements Serializable, UIResource
771
  {
772
    /**
773
     * Determined using the <code>serialver</code> tool
774
     * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
775
     */
776
    static final long serialVersionUID = -3035848353448896090L;
777
 
778
 
779
    /**
780
     * Constructs a new MarginBorder.
781
     */
782
    public MarginBorder()
783
    {
784
      // Nothing to do here.
785
    }
786
 
787
    /**
788
     * Measures the width of this border.
789
     *
790
     * @param c the component whose border is to be measured.
791
     *
792
     * @return an Insets object whose <code>left</code>, <code>right</code>,
793
     *         <code>top</code> and <code>bottom</code> fields indicate the
794
     *         width of the border at the respective edge.
795
     *
796
     * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
797
     */
798
    public Insets getBorderInsets(Component c)
799
    {
800
      return getBorderInsets(c, new Insets(0, 0, 0, 0));
801
    }
802
 
803
 
804
    /**
805
     * Determines the insets of this border by calling the
806
     * <code>getMargin()</code> method of the enclosed component.  The
807
     * resulting margin will be stored into the the <code>left</code>,
808
     * <code>right</code>, <code>top</code> and <code>bottom</code>
809
     * fields of the passed <code>insets</code> parameter.
810
     *
811
     * <p>Unfortunately, <code>getMargin()</code> is not a method of
812
     * {@link javax.swing.JComponent} or some other common superclass
813
     * of things with margins. While reflection could be used to
814
     * determine the existence of this method, this would be slow on
815
     * many virtual machines. Therefore, the current implementation
816
     * knows about {@link javax.swing.AbstractButton#getMargin()},
817
     * {@link javax.swing.JPopupMenu#getMargin()}, {@link
818
     * javax.swing.JToolBar#getMargin()}, and {@link
819
     * javax.swing.text.JTextComponent}. If <code>c</code> is an
820
     * instance of a known class, the respective
821
     * <code>getMargin()</code> method is called to determine the
822
     * correct margin. Otherwise, a zero-width margin is returned.
823
     *
824
     * @param c the component whose border is to be measured.
825
     *
826
     * @return the same object that was passed for <code>insets</code>,
827
     *         but with changed fields.
828
     */
829
    public Insets getBorderInsets(Component c, Insets insets)
830
    {
831
      Insets margin = null;
832
 
833
      /* This is terrible object-oriented design. See the above Javadoc
834
       * for an excuse.
835
       */
836
      if (c instanceof AbstractButton)
837
        margin = ((AbstractButton) c).getMargin();
838
      else if (c instanceof JPopupMenu)
839
        margin = ((JPopupMenu) c).getMargin();
840
      else if (c instanceof JToolBar)
841
        margin = ((JToolBar) c).getMargin();
842
      else if (c instanceof JTextComponent)
843
        margin = ((JTextComponent) c).getMargin();
844
 
845
      if (margin == null)
846
        insets.top = insets.left = insets.bottom = insets.right = 0;
847
      else
848
      {
849
        insets.top = margin.top;
850
        insets.left = margin.left;
851
        insets.bottom = margin.bottom;
852
        insets.right = margin.right;
853
      }
854
 
855
      return insets;
856
    }
857
  }
858
 
859
 
860
  /**
861
   * A border for drawing a separator line below JMenuBar.
862
   *
863
   * <p><img src="doc-files/BasicBorders.MenuBarBorder-1.png" width="500"
864
   * height="140" alt="[A screen shot of a JMenuBar with this border]" />
865
   *
866
   * @author Sascha Brawer (brawer@dandelis.ch)
867
   */
868
  public static class MenuBarBorder
869
    extends AbstractBorder
870
    implements UIResource
871
  {
872
    /**
873
     * Determined using the <code>serialver</code> tool
874
     * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
875
     */
876
    static final long serialVersionUID = -6909056571935227506L;
877
 
878
 
879
    /**
880
     * The shadow color, which is used for the upper line of the
881
     * two-pixel thick bottom edge.
882
     */
883
    private Color shadow;
884
 
885
 
886
    /**
887
     * The highlight color, which is used for the lower line of the
888
     * two-pixel thick bottom edge.
889
     */
890
    private Color highlight;
891
 
892
 
893
    /**
894
     * Constructs a new MenuBarBorder for drawing a JMenuBar in
895
     * the Basic look and feel.
896
     *
897
     * <p><img src="doc-files/BasicBorders.MenuBarBorder-1.png" width="500"
898
     * height="140" alt="[A screen shot of a JMenuBar with this
899
     * border]" />
900
     *
901
     * @param shadow the shadow color, which is used for the upper
902
     *        line of the two-pixel thick bottom edge.
903
     *
904
     * @param highlight the shadow color, which is used for the lower
905
     *        line of the two-pixel thick bottom edge.
906
     */
907
    public MenuBarBorder(Color shadow, Color highlight)
908
    {
909
      /* These colors usually come from the UIDefaults of the current
910
       * look and feel. Use fallback values if the colors are not
911
       * supplied.  The API specification is silent about what
912
       * behavior is expected for null colors, so users should not
913
       * rely on this fallback (which is why it is not documented in
914
       * the above Javadoc).
915
       */
916
      this.shadow = (shadow != null) ? shadow : Color.gray;
917
      this.highlight = (highlight != null) ? highlight : Color.white;
918
    }
919
 
920
 
921
    /**
922
     * Paints the MenuBarBorder around a given component.
923
     *
924
     * @param c the component whose border is to be painted, usually
925
     *        an instance of {@link javax.swing.JMenuBar}.
926
     *
927
     * @param g the graphics for painting.
928
     * @param x the horizontal position for painting the border.
929
     * @param y the vertical position for painting the border.
930
     * @param width the width of the available area for painting the border.
931
     * @param height the height of the available area for painting the border.
932
     */
933
    public void paintBorder(Component c, Graphics  g,
934
                            int x, int y, int width, int height)
935
    {
936
      Color oldColor;
937
 
938
      /* To understand this code, it might be helpful to look at the
939
       * image "BasicBorders.MenuBarBorder-1.png" that is included
940
       * with the JavaDoc. It is located in the "doc-files"
941
       * subdirectory.
942
       */
943
      oldColor = g.getColor();
944
      y = y + height - 2;
945
      try
946
      {
947
        g.setColor(shadow);
948
        g.drawLine(x, y, x + width - 2, y);
949
        g.drawLine(x, y + 1, x, y + 1);
950
        g.drawLine(x + width - 2, y + 1, x + width - 2, y + 1);
951
 
952
        g.setColor(highlight);
953
        g.drawLine(x + 1, y + 1, x + width - 3, y + 1);
954
        g.drawLine(x + width - 1, y, x + width - 1, y + 1);
955
      }
956
      finally
957
      {
958
        g.setColor(oldColor);
959
      }
960
    }
961
 
962
 
963
    /**
964
     * Measures the width of this border.
965
     *
966
     * @param c the component whose border is to be measured.
967
     *
968
     * @return an Insets object whose <code>left</code>,
969
     *         <code>right</code>, <code>top</code> and
970
     *         <code>bottom</code> fields indicate the width of the
971
     *         border at the respective edge.
972
     *
973
     * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
974
     */
975
    public Insets getBorderInsets(Component c)
976
    {
977
      /* There is no obvious reason for overriding this method, but we
978
       * try to have exactly the same API as the Sun reference
979
       * implementation.
980
       */
981
      return getBorderInsets(c, null);
982
    }
983
 
984
 
985
    /**
986
     * Measures the width of this border, storing the results into a
987
     * pre-existing Insets object.
988
     *
989
     * @param insets an Insets object for holding the result values.
990
     *        After invoking this method, the <code>left</code>,
991
     *        <code>right</code>, <code>top</code> and
992
     *        <code>bottom</code> fields indicate the width of the
993
     *        border at the respective edge.
994
     *
995
     * @return the same object that was passed for <code>insets</code>.
996
     *
997
     * @see #getBorderInsets(Component)
998
     */
999
    public Insets getBorderInsets(Component c, Insets insets)
1000
    {
1001
      /* The exact amount has been determined using a test program
1002
       * that was run on the Apple/Sun JDK 1.3.1 on MacOS X, and the
1003
       * Sun JDK 1.4.1_01 on GNU/Linux for x86. Both gave [0,0,2,0],
1004
       * which was expected from looking at the screen shot.
1005
       */
1006
      if (insets == null)
1007
        return new Insets(0, 0, 2, 0);
1008
 
1009
      insets.left = insets.right = insets.top = 0;
1010
      insets.bottom = 2;
1011
      return insets;
1012
    }
1013
  }
1014
 
1015
 
1016
  /**
1017
   * A border for drawing radio buttons in the Basic look and feel.
1018
   *
1019
   * <p><img src="doc-files/BasicBorders.RadioButtonBorder-1.png" width="300"
1020
   * height="135" alt="[A screen shot of this border]" />
1021
   *
1022
   * <p>Note about the screen shot: Normally, the
1023
   * <code>borderPainted</code> property is <code>false</code> for
1024
   * JRadioButtons. For this screen shot, it has been set to
1025
   * <code>true</code> so the borders get drawn. Also, a
1026
   * concretization of the Basic look and would typically provide
1027
   * icons for the various states of radio buttons.
1028
   *
1029
   * <p>Note that the focus rectangle is invisible If the radio button
1030
   * is currently selected. While it might be debatable whether this
1031
   * makes a lot of sense, this behavior can be observed in the Sun
1032
   * reference implementation (in JDK 1.3.1 and 1.4.1). The Classpath
1033
   * implementation tries to exactly replicate the JDK appearance.
1034
   *
1035
   * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel
1036
   *
1037
   * @author Sascha Brawer (brawer@dandelis.ch)
1038
   */
1039
  public static class RadioButtonBorder
1040
    extends ButtonBorder
1041
  {
1042
    /**
1043
     * Determined using the <code>serialver</code> tool
1044
     * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
1045
     */
1046
    static final long serialVersionUID = 1596945751743747369L;
1047
 
1048
 
1049
    /**
1050
     * Constructs a new border for drawing a JRadioButton in
1051
     * the Basic look and feel.
1052
     *
1053
     * @param shadow the shadow color.
1054
     * @param darkShadow a darker variant of the shadow color.
1055
     * @param highlight the highlight color.
1056
     * @param lightHighlight a brighter variant of the highlight  color.
1057
     */
1058
    public RadioButtonBorder(Color shadow, Color darkShadow,
1059
                             Color highlight, Color lightHighlight)
1060
    {
1061
      /* The superclass ButtonBorder substitutes null arguments
1062
       * with fallback colors.
1063
       */
1064
      super(shadow, darkShadow, highlight, lightHighlight);
1065
    }
1066
 
1067
 
1068
    /**
1069
     * Paints the RadioButtonBorder around a given component.
1070
     *
1071
     * <p>The Sun implementation always seems to draw exactly
1072
     * the same border, irrespective of the state of the button.
1073
     * This is rather surprising, but GNU Classpath emulates the
1074
     * observable behavior.
1075
     *
1076
     * @param c the component whose border is to be painted.
1077
     * @param g the graphics for painting.
1078
     * @param x the horizontal position for painting the border.
1079
     * @param y the vertical position for painting the border.
1080
     * @param width the width of the available area for painting the border.
1081
     * @param height the height of the available area for painting the border.
1082
     *
1083
     * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel
1084
     */
1085
    public void paintBorder(Component c, Graphics  g,
1086
                            int x, int y, int width, int height)
1087
    {
1088
      AbstractButton button = null;
1089
      ButtonModel bmodel = null;
1090
      boolean lowered = false;
1091
      boolean focused = false;
1092
 
1093
      if (c instanceof AbstractButton)
1094
      {
1095
        button = (AbstractButton) c;
1096
        bmodel = button.getModel();
1097
      }
1098
 
1099
      if (bmodel != null)
1100
      {
1101
        lowered = button.isSelected()
1102
          || (/* mouse inside */ bmodel.isArmed() && bmodel.isPressed());
1103
        focused = button.hasFocus() && button.isFocusPainted();
1104
      }
1105
 
1106
      if (lowered)
1107
        BasicGraphicsUtils.drawLoweredBezel(g, x, y, width, height,
1108
                                            shadow, darkShadow,
1109
                                            highlight, lightHighlight);
1110
      else
1111
        BasicGraphicsUtils.drawBezel(g, x, y, width, height,
1112
                                     /* isPressed */ false,
1113
                                     /* isPefault */ focused,
1114
                                     shadow, darkShadow,
1115
                                     highlight, lightHighlight);
1116
    }
1117
 
1118
 
1119
    /**
1120
     * Measures the width of this border.
1121
     *
1122
     * @param c the component whose border is to be measured.
1123
     *
1124
     * @return an Insets object whose <code>left</code>,
1125
     *         <code>right</code>, <code>top</code> and
1126
     *         <code>bottom</code> fields indicate the width of the
1127
     *         border at the respective edge.
1128
     *
1129
     * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
1130
     */
1131
    public Insets getBorderInsets(Component c)
1132
    {
1133
      /* There is no obvious reason for overriding this method, but we
1134
       * try to have exactly the same API as the Sun reference
1135
       * implementation.
1136
       */
1137
      return getBorderInsets(c, null);
1138
    }
1139
 
1140
 
1141
    /**
1142
     * Measures the width of this border, storing the results into a
1143
     * pre-existing Insets object.
1144
     *
1145
     * @param insets an Insets object for holding the result values.
1146
     *        After invoking this method, the <code>left</code>,
1147
     *        <code>right</code>, <code>top</code> and
1148
     *        <code>bottom</code> fields indicate the width of the
1149
     *        border at the respective edge.
1150
     *
1151
     * @return the same object that was passed for <code>insets</code>.
1152
     *
1153
     * @see #getBorderInsets(Component)
1154
     */
1155
    public Insets getBorderInsets(Component c, Insets insets)
1156
    {
1157
      /* The exact amount has been determined using a test program
1158
       * that was run on the Apple/Sun JDK 1.3.1 on MacOS X, and the
1159
       * Sun JDK 1.4.1_01 on GNU/Linux for x86. Both gave [2,2,2,2].
1160
       */
1161
      if (insets == null)
1162
        return new Insets(2, 2, 2, 2);
1163
 
1164
      insets.left = insets.right = insets.top = insets.bottom = 2;
1165
      return insets;
1166
    }
1167
  }
1168
 
1169
 
1170
  /**
1171
   * A one-pixel thick border for rollover buttons, for example in
1172
   * tool bars.
1173
   *
1174
   * @since 1.4
1175
   * @author Sascha Brawer (brawer@dandelis.ch)
1176
   */
1177
  public static class RolloverButtonBorder
1178
    extends ButtonBorder
1179
  {
1180
    /**
1181
     * Determined using the <code>serialver</code> tool
1182
     * of Sun JDK 1.4.1_01 on GNU/Linux 2.4.20 for x86.
1183
     */
1184
    static final long serialVersionUID = 1976364864896996846L;
1185
 
1186
 
1187
    /**
1188
     * Constructs a new border for drawing a roll-over button
1189
     * in the Basic look and feel.
1190
     *
1191
     * @param shadow the shadow color.
1192
     * @param darkShadow a darker variant of the shadow color.
1193
     * @param highlight the highlight color.
1194
     * @param lightHighlight a brighter variant of the highlight  color.
1195
     */
1196
    public RolloverButtonBorder(Color shadow, Color darkShadow,
1197
                                Color highlight, Color lightHighlight)
1198
    {
1199
      super(shadow, darkShadow, highlight, lightHighlight);
1200
    }
1201
 
1202
 
1203
    /**
1204
     * Paints the border around a rollover button.  If <code>c</code>
1205
     * is not an {@link javax.swing.AbstractButton} whose model
1206
     * returns <code>true</code> for {@link
1207
     * javax.swing.ButtonModel#isRollover}, nothing gets painted at
1208
     * all.
1209
     *
1210
     * @param c the button whose border is to be painted.
1211
     * @param g the graphics for painting.
1212
     * @param x the horizontal position for painting the border.
1213
     * @param y the vertical position for painting the border.
1214
     * @param width the width of the available area for painting the border.
1215
     * @param height the height of the available area for painting the border.
1216
     */
1217
    public void paintBorder(Component c, Graphics  g,
1218
                            int x, int y, int width, int height)
1219
    {
1220
      ButtonModel bmodel = null;
1221
      boolean drawPressed;
1222
      Color oldColor = g.getColor();
1223
      int x2, y2;
1224
 
1225
      if (c instanceof AbstractButton)
1226
        bmodel = ((AbstractButton) c).getModel();
1227
 
1228
      /* Draw nothing if c is not a rollover button. */
1229
      if ((bmodel == null) || !bmodel.isRollover())
1230
        return;
1231
 
1232
      /* Draw nothing if the mouse is pressed, but outside the button. */
1233
      if (bmodel.isPressed() && !bmodel.isArmed())
1234
        return;
1235
 
1236
      drawPressed = bmodel.isSelected() || bmodel.isPressed();
1237
      x2 = x + width - 1;
1238
      y2 = y + height - 1;
1239
 
1240
      try
1241
      {
1242
        g.setColor(drawPressed ? shadow : lightHighlight);
1243
        g.drawLine(x, y, x2 - 1, y);     // top edge
1244
        g.drawLine(x, y + 1, x, y2 - 1); // left edge
1245
 
1246
        g.setColor(drawPressed ? lightHighlight : shadow);
1247
        g.drawLine(x, y2, x2, y2);       // bottom edge
1248
        g.drawLine(x2, y, x2, y2 - 1);   // right edge
1249
      }
1250
      finally
1251
      {
1252
        g.setColor(oldColor);
1253
      }
1254
    }
1255
  }
1256
 
1257
 
1258
  /**
1259
   * A border for JSplitPanes in the Basic look and feel. The divider
1260
   * in the middle of the JSplitPane has its own border class, of which
1261
   * an instance can be obtained with {@link #getSplitPaneDividerBorder()}.
1262
   *
1263
   * <p><img src="doc-files/BasicBorders.SplitPaneBorder-1.png" width="520"
1264
   * height="200" alt="[A screen shot for JSplitPane.HORIZONTAL_SPLIT]" />
1265
   *
1266
   * <p><img src="doc-files/BasicBorders.SplitPaneBorder-2.png" width="520"
1267
   * height="200" alt="[A screen shot for JSplitPane.VERTICAL_SPLIT]" />
1268
   *
1269
   * <p>In contrast to the other borders of the Basic look and feel,
1270
   * this class is not serializable. While this might be unintended,
1271
   * GNU Classpath follows the specification in order to be fully
1272
   * compatible with the Sun reference implementation.
1273
   *
1274
   * <p>In the Sun JDK, the bottom edge of the divider also gets
1275
   * painted if the orientation of the enclosed JSplitPane is
1276
   * <code>JSplitPane.VERTICAL_SPLIT</code> (at least in versions
1277
   * 1.3.1 and 1.4.1).  GNU Classpath does not replicate this bug. A
1278
   * report has been filed with Sun (bug ID 4885629).
1279
   *
1280
   * <p>Note that the bottom left pixel of the border has a different
1281
   * color depending on the orientation of the enclosed JSplitPane.
1282
   * Although this is visually inconsistent, Classpath replicates the
1283
   * appearance of the Sun reference implementation. A bug report has
1284
   * been filed with Sun (review ID 188774).
1285
   *
1286
   * @see #getSplitPaneBorder()
1287
   * @see #getSplitPaneDividerBorder()
1288
   *
1289
   * @author Sascha Brawer (brawer@dandelis.ch)
1290
   */
1291
  public static class SplitPaneBorder implements Border, UIResource
1292
  {
1293
    /**
1294
     * Indicates that the top edge shall be not be painted
1295
     * by {@link #paintRect}.
1296
     */
1297
    private static final int SUPPRESS_TOP = 1;
1298
 
1299
 
1300
    /**
1301
     * Indicates that the left edge shall be not be painted
1302
     * by {@link #paintRect}.
1303
     */
1304
    private static final int SUPPRESS_LEFT = 2;
1305
 
1306
 
1307
    /**
1308
     * Indicates that the bottom edge shall be not be painted
1309
     * by {@link #paintRect}.
1310
     */
1311
    private static final int SUPPRESS_BOTTOM = 4;
1312
 
1313
 
1314
    /**
1315
     * Indicates that the right edge shall be not be painted
1316
     * by {@link #paintRect}.
1317
     */
1318
    private static final int SUPPRESS_RIGHT = 8;
1319
 
1320
 
1321
    /**
1322
     * The color for drawing the bottom and right edges of the border.
1323
     */
1324
    protected Color highlight;
1325
 
1326
 
1327
    /**
1328
     * The color for drawing the top and left edges of the border.
1329
     */
1330
    protected Color shadow;
1331
 
1332
 
1333
    /**
1334
     * Constructs a new border for drawing a JSplitPane in the Basic
1335
     * look and feel.  The divider in the middle of the JSplitPane has
1336
     * its own border class, <code>SplitPaneDividerBorder</code>.
1337
     *
1338
     * @param shadow the shadow color.
1339
     * @param highlight the highlight color.
1340
     */
1341
    public SplitPaneBorder(Color highlight, Color shadow)
1342
    {
1343
      /* These colors usually come from the UIDefaults of the current
1344
       * look and feel. Use fallback values if the colors are not
1345
       * supplied.  The API specification is silent about what
1346
       * behavior is expected for null colors, so users should not
1347
       * rely on this fallback (which is why it is not documented in
1348
       * the above Javadoc).
1349
       */
1350
      this.shadow = (shadow != null) ? shadow : Color.black;
1351
      this.highlight = (highlight != null) ? highlight : Color.white;
1352
    }
1353
 
1354
 
1355
    /**
1356
     * Paints the border around a <code>JSplitPane</code>.
1357
     *
1358
     * <p><img src="doc-files/BasicBorders.SplitPaneBorder-1.png" width="520"
1359
     * height="200" alt="[A screen shot for JSplitPane.HORIZONTAL_SPLIT]" />
1360
     *
1361
     * <p><img src="doc-files/BasicBorders.SplitPaneBorder-2.png" width="520"
1362
     * height="200" alt="[A screen shot for JSplitPane.VERTICAL_SPLIT]" />
1363
     *
1364
     * @param c the <code>JSplitPane</code> whose border is to be painted.
1365
     * @param g the graphics for painting.
1366
     * @param x the horizontal position for painting the border.
1367
     * @param y the vertical position for painting the border.
1368
     * @param width the width of the available area for painting the border.
1369
     * @param height the height of the available area for painting the border.
1370
     */
1371
    public void paintBorder(Component c, Graphics  g,
1372
                            int x, int y, int width, int height)
1373
    {
1374
      JSplitPane splitPane;
1375
      Component content;
1376
 
1377
      if (!(c instanceof JSplitPane))
1378
        return;
1379
 
1380
      splitPane = (JSplitPane) c;
1381
      switch (splitPane.getOrientation())
1382
      {
1383
      case JSplitPane.HORIZONTAL_SPLIT:
1384
        if ((content = splitPane.getLeftComponent()) != null)
1385
          paintRect(g, SUPPRESS_RIGHT, true, x, y, content.getBounds());
1386
        if ((content = splitPane.getRightComponent()) != null)
1387
          paintRect(g, SUPPRESS_LEFT, true, x, y, content.getBounds());
1388
        break;
1389
 
1390
      case JSplitPane.VERTICAL_SPLIT:
1391
        if ((content = splitPane.getTopComponent()) != null)
1392
          paintRect(g, SUPPRESS_BOTTOM, false, x, y, content.getBounds());
1393
        if ((content = splitPane.getBottomComponent()) != null)
1394
          paintRect(g, SUPPRESS_TOP, false, x, y, content.getBounds());
1395
        break;
1396
      }
1397
    }
1398
 
1399
 
1400
    /**
1401
     * Paints a border around a child of a <code>JSplitPane</code>,
1402
     * omitting some of the edges.
1403
     *
1404
     * @param g the graphics for painting.
1405
     *
1406
     * @param suppress a bit mask indicating the set of suppressed
1407
     *        edges, for example <code>SUPPRESS_TOP | SUPPRESS_RIGHT</code>.
1408
     *
1409
     * @param x the x coordinate of the SplitPaneBorder.
1410
     *
1411
     * @param y the y coordinate of the SplitPaneBorder.
1412
     *
1413
     * @param shadeBottomLeftPixel <code>true</code> to paint the
1414
     *        bottom left pixel in the shadow color,
1415
     *        <code>false</code> for the highlight color. The Basic
1416
     *        look and feel uses the highlight color for the bottom
1417
     *        left pixel of the border of a JSplitPane whose
1418
     *        orientation is VERTICAL_SPLIT, and the shadow color
1419
     *        otherwise. While this might be a strange distinction,
1420
     *        Classpath tries to look identical to the reference
1421
     *        implementation. A bug report has been filed with Sun;
1422
     *        its review ID is 188774. We currently replicate the
1423
     *        Sun behavior.
1424
     *
1425
     * @param rect the bounds of the child of JSplitPane whose
1426
     *        border is to be painted.
1427
     */
1428
    private void paintRect(Graphics g, int suppress,
1429
                           boolean shadeBottomLeftPixel,
1430
                           int x, int y,
1431
                           Rectangle rect)
1432
    {
1433
      if (rect == null)
1434
        return;
1435
 
1436
      /* On each edge, the border exceeds the enclosed child by one
1437
       * pixel. See the image "BasicBorders.SplitPaneBorder-1.png" in
1438
       * the directory "doc-files".
1439
       */
1440
      x += rect.x - 1;
1441
      y += rect.y - 1;
1442
      int right = x + rect.width + 1;
1443
      int bottom = y + rect.height + 1;
1444
 
1445
      Color oldColor = g.getColor();
1446
      try
1447
      {
1448
        g.setColor(shadow);
1449
        if ((suppress & SUPPRESS_TOP) == 0)
1450
          g.drawLine(x, y, right, y);
1451
        if ((suppress & SUPPRESS_LEFT) == 0)
1452
          g.drawLine(x, y, x, bottom);
1453
        else
1454
          g.drawLine(x, bottom, x, bottom); // one pixel
1455
 
1456
        g.setColor(highlight);
1457
        if ((suppress & SUPPRESS_BOTTOM) == 0)
1458
          g.drawLine(x + (shadeBottomLeftPixel ? 1 : 0), bottom, right, bottom);
1459
        else if (!shadeBottomLeftPixel)
1460
          g.drawLine(x, bottom, x, bottom); // one pixel
1461
 
1462
        if ((suppress & SUPPRESS_RIGHT) == 0)
1463
          g.drawLine(right, y, right, bottom);
1464
      }
1465
      finally
1466
      {
1467
        g.setColor(oldColor);
1468
      }
1469
    }
1470
 
1471
 
1472
    /**
1473
     * Measures the width of this border.
1474
     *
1475
     * @param c the component whose border is to be measured, usually
1476
     *        an instance of {@link javax.swing.JSplitPane}.
1477
     *
1478
     * @return an Insets object whose <code>left</code>,
1479
     *         <code>right</code>, <code>top</code> and
1480
     *         <code>bottom</code> fields indicate the width of the
1481
     *         border at the respective edge.
1482
     */
1483
    public Insets getBorderInsets(Component c)
1484
    {
1485
      return new Insets(1, 1, 1, 1);
1486
    }
1487
 
1488
 
1489
    /**
1490
     * Determines whether this border fills every pixel in its area
1491
     * when painting.
1492
     *
1493
     * @return <code>false</code> because this border does not
1494
     *         paint over the pixels where the divider joins
1495
     *         the border.
1496
     */
1497
    public boolean isBorderOpaque()
1498
    {
1499
      /* Strangely, the Sun implementation (tested with JDK 1.3.1 and
1500
       * 1.4.1_01) seems to always return true. It could be a bug,
1501
       * but without knowing the details of their implementation, it is
1502
       * hard to decide.
1503
       */
1504
      return false;
1505
    }
1506
  }
1507
 
1508
 
1509
  /**
1510
   * A border for the divider inside a JSplitPane.
1511
   *
1512
   * <p><img src="doc-files/BasicBorders.SplitPaneDividerBorder-1.png"
1513
   * width="520" height="200" alt="[A screen shot of this border]" />
1514
   *
1515
   * @author Sascha Brawer (brawer@dandelis.ch)
1516
   */
1517
  private static class SplitPaneDividerBorder
1518
    implements Border, UIResource, Serializable
1519
  {
1520
    /**
1521
     * The highlight color, which is drawn on the left or top edge
1522
     * depending on the orientation of the JSplitPanel.
1523
     */
1524
    protected Color highlight;
1525
 
1526
 
1527
    /**
1528
     * The highlight color, which is drawn on the right or bottom edge
1529
     * depending on the orientation of the JSplitPanel.
1530
     */
1531
    protected Color shadow;
1532
 
1533
 
1534
    /**
1535
     * Constructs a new border for drawing the divider of a JSplitPane
1536
     * in the Basic look and feel.  The outer parts of the JSplitPane have
1537
     * their own border class, <code>SplitPaneBorder</code>.
1538
     *
1539
     * @param shadow the shadow color.
1540
     * @param highlight the highlight color.
1541
     */
1542
    public SplitPaneDividerBorder(Color highlight, Color shadow)
1543
    {
1544
      this.highlight = (highlight != null) ? highlight : Color.white;
1545
      this.shadow = (shadow != null) ? shadow : Color.black;
1546
    }
1547
 
1548
 
1549
    /**
1550
     * Paints the border around the divider of a <code>JSplitPane</code>.
1551
     *
1552
     * <p><img src="doc-files/BasicBorders.SplitPaneDividerBorder-1.png"
1553
     * width="520" height="200" alt="[A picture that shows which pixels
1554
     * get painted in what color]" />
1555
     *
1556
     * @param c the <code>JSplitPane</code> whose divider&#x2019;s border
1557
     *        is to be painted.
1558
     * @param g the graphics for painting.
1559
     * @param x the horizontal position for painting the border.
1560
     * @param y the vertical position for painting the border.
1561
     * @param width the width of the available area for painting the border.
1562
     * @param height the height of the available area for painting the border.
1563
     */
1564
    public void paintBorder(Component c, Graphics  g,
1565
                            int x, int y, int width, int height)
1566
    {
1567
      Color oldColor, dcol;
1568
      int x2, y2;
1569
      JSplitPane sp;
1570
 
1571
      sp = getSplitPane(c);
1572
      if (sp == null)
1573
        return;
1574
 
1575
      x2 = x + width - 1;
1576
      y2 = y + height - 1;
1577
      oldColor = g.getColor();
1578
      dcol = c.getBackground();
1579
      try
1580
      {
1581
        switch (sp.getOrientation())
1582
        {
1583
        case JSplitPane.HORIZONTAL_SPLIT:
1584
          g.setColor(dcol);
1585
          g.drawLine(x + 1, y, x2 - 1, y);
1586
          g.drawLine(x + 1, y2, x2 - 1, y2);
1587
          g.setColor(sp.getLeftComponent() != null ? highlight : dcol);
1588
          g.drawLine(x, y, x, y2);
1589
          g.setColor(sp.getRightComponent() != null ? shadow : dcol);
1590
          g.drawLine(x2, y, x2, y2);
1591
          break;
1592
 
1593
        case JSplitPane.VERTICAL_SPLIT:
1594
          g.setColor(dcol);
1595
          g.drawLine(x, y + 1, x, y2 - 1);
1596
          g.drawLine(x2, y + 1, x2, y2 - 1);
1597
          g.setColor(sp.getTopComponent() != null ? highlight : dcol);
1598
          g.drawLine(x, y, x2, y);
1599
          g.setColor(sp.getBottomComponent() != null ? shadow : dcol);
1600
          g.drawLine(x, y2, x2, y2);
1601
          break;
1602
        }
1603
      }
1604
      finally
1605
      {
1606
        g.setColor(oldColor);
1607
      }
1608
    }
1609
 
1610
 
1611
    /**
1612
     * Measures the width of this border.
1613
     *
1614
     * @param c the component whose border is to be measured, usually
1615
     *        an instance of {@link javax.swing.JSplitPane}.
1616
     *
1617
     * @return an Insets object whose <code>left</code>,
1618
     *         <code>right</code>, <code>top</code> and
1619
     *         <code>bottom</code> fields indicate the width of the
1620
     *         border at the respective edge.
1621
     */
1622
    public Insets getBorderInsets(Component c)
1623
    {
1624
      return new Insets(1, 1, 1, 1);
1625
    }
1626
 
1627
 
1628
    /**
1629
     * Determines whether this border fills every pixel in its area
1630
     * when painting.
1631
     *
1632
     * @return <code>true</code> if both highlight and shadow
1633
     *         color are fully opaque.
1634
     */
1635
    public boolean isBorderOpaque()
1636
    {
1637
      return (highlight.getAlpha() == 255) && (shadow.getAlpha() == 255);
1638
    }
1639
 
1640
 
1641
    /**
1642
     * Determines the JSplitPane whose divider is being painted.
1643
     *
1644
     * @param c an instance of BasicSplitPaneDivider.
1645
     *
1646
     * @return a <code>JSplitPane</code>, or <code>null</code> if
1647
     *         <code>c</code> is not an instance of {@link
1648
     *         javax.swing.plaf.basic.BasicSplitPaneDivider}.
1649
     */
1650
    private JSplitPane getSplitPane(Component c)
1651
    {
1652
      if (c instanceof BasicSplitPaneDivider)
1653
        return (((BasicSplitPaneDivider) c).getBasicSplitPaneUI())
1654
          .getSplitPane();
1655
      else
1656
        return null;
1657
    }
1658
  }
1659
 
1660
 
1661
  /**
1662
   * A border for toggle buttons in the Basic look and feel.
1663
   *
1664
   * <p><img src="doc-files/BasicBorders.ToggleButtonBorder-1.png"
1665
   * width="270" height="135" alt="[A screen shot of this border]" />
1666
   *
1667
   * <p>The Sun implementation always seems to draw exactly
1668
   * the same border, irrespective of the state of the button.
1669
   * This is rather surprising, but GNU Classpath emulates the
1670
   * observable behavior.
1671
   *
1672
   * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel
1673
   *
1674
   * @author Sascha Brawer (brawer@dandelis.ch)
1675
   */
1676
  public static class ToggleButtonBorder
1677
    extends ButtonBorder
1678
  {
1679
    /**
1680
     * Determined using the <code>serialver</code> tool
1681
     * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
1682
     */
1683
    static final long serialVersionUID = -3528666548001058394L;
1684
 
1685
 
1686
    /**
1687
     * Constructs a new border for drawing a JToggleButton in
1688
     * the Basic look and feel.
1689
     *
1690
     * @param shadow the shadow color.
1691
     * @param darkShadow a darker variant of the shadow color.
1692
     * @param highlight the highlight color.
1693
     * @param lightHighlight a brighter variant of the highlight  color.
1694
     */
1695
    public ToggleButtonBorder(Color shadow, Color darkShadow,
1696
                              Color highlight, Color lightHighlight)
1697
    {
1698
      /* The superclass ButtonBorder substitutes null arguments
1699
       * with fallback colors.
1700
       */
1701
      super(shadow, darkShadow, highlight, lightHighlight);
1702
    }
1703
 
1704
 
1705
    /**
1706
     * Paints the ToggleButtonBorder around a given component.
1707
     *
1708
     * <p>The Sun implementation always seems to draw exactly
1709
     * the same border, irrespective of the state of the button.
1710
     * This is rather surprising, but GNU Classpath emulates the
1711
     * observable behavior.
1712
     *
1713
     * @param c the component whose border is to be painted.
1714
     * @param g the graphics for painting.
1715
     * @param x the horizontal position for painting the border.
1716
     * @param y the vertical position for painting the border.
1717
     * @param width the width of the available area for painting the border.
1718
     * @param height the height of the available area for painting the border.
1719
     *
1720
     * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel
1721
     */
1722
    public void paintBorder(Component c, Graphics  g,
1723
                            int x, int y, int width, int height)
1724
    {
1725
      /* The author of this code tried various variants for setting
1726
       * the state of the enclosed JToggleButton, but it seems that
1727
       * the drawn border is always identical. Weird, because this
1728
       * means that the user does not see whether the JToggleButton
1729
       * is selected or not.
1730
       */
1731
      BasicGraphicsUtils.drawBezel(g, x, y, width, height,
1732
                                   /* pressed */ false,
1733
                                   /* default */ false,
1734
                                   shadow, darkShadow,
1735
                                   highlight, lightHighlight);
1736
    }
1737
 
1738
 
1739
    /**
1740
     * Measures the width of this border.
1741
     *
1742
     * @param c the component whose border is to be measured.
1743
     *
1744
     * @return an Insets object whose <code>left</code>,
1745
     *         <code>right</code>, <code>top</code> and
1746
     *         <code>bottom</code> fields indicate the width of the
1747
     *         border at the respective edge.
1748
     *
1749
     * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
1750
     */
1751
    public Insets getBorderInsets(Component c)
1752
    {
1753
      /* There is no obvious reason for overriding this method, but we
1754
       * try to have exactly the same API as the Sun reference
1755
       * implementation.
1756
       */
1757
      return getBorderInsets(c, null);
1758
    }
1759
 
1760
 
1761
    /**
1762
     * Measures the width of this border, storing the results into a
1763
     * pre-existing Insets object.
1764
     *
1765
     * @param insets an Insets object for holding the result values.
1766
     *        After invoking this method, the <code>left</code>,
1767
     *        <code>right</code>, <code>top</code> and
1768
     *        <code>bottom</code> fields indicate the width of the
1769
     *        border at the respective edge.
1770
     *
1771
     * @return the same object that was passed for <code>insets</code>.
1772
     *
1773
     * @see #getBorderInsets(Component)
1774
     */
1775
    public Insets getBorderInsets(Component c, Insets insets)
1776
    {
1777
      /* The exact amount has been determined using a test program
1778
       * that was run on the Apple/Sun JDK 1.3.1 on MacOS X, and the
1779
       * Sun JDK 1.4.1_01 on GNU/Linux for x86. Both gave [2,2,2,2].
1780
       */
1781
      if (insets == null)
1782
        return new Insets(2, 2, 2, 2);
1783
 
1784
      insets.left = insets.right = insets.top = insets.bottom = 2;
1785
      return insets;
1786
    }
1787
  }
1788
}

powered by: WebSVN 2.1.0

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