001/* MetalBorders.java
002   Copyright (C) 2005, 2006, Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.swing.plaf.metal;
040
041import java.awt.Color;
042import java.awt.Component;
043import java.awt.Graphics;
044import java.awt.Insets;
045
046import javax.swing.AbstractButton;
047import javax.swing.ButtonModel;
048import javax.swing.JButton;
049import javax.swing.JInternalFrame;
050import javax.swing.JMenu;
051import javax.swing.JMenuBar;
052import javax.swing.JMenuItem;
053import javax.swing.JOptionPane;
054import javax.swing.JScrollPane;
055import javax.swing.JTextField;
056import javax.swing.JToggleButton;
057import javax.swing.JToolBar;
058import javax.swing.SwingConstants;
059import javax.swing.UIManager;
060import javax.swing.border.AbstractBorder;
061import javax.swing.border.Border;
062import javax.swing.border.CompoundBorder;
063import javax.swing.plaf.BorderUIResource;
064import javax.swing.plaf.UIResource;
065import javax.swing.plaf.basic.BasicBorders;
066import javax.swing.text.JTextComponent;
067
068
069/**
070 * A factory class that creates borders for the different Swing components.
071 *
072 * @author Roman Kennke (roman@kennke.org)
073 */
074public class MetalBorders
075{
076
077  /** The shared instance for getButtonBorder(). */
078  private static Border buttonBorder;
079
080  /** The shared instance for getToggleButtonBorder(). */
081  private static Border toggleButtonBorder;
082
083  /** The shared instance for getDesktopIconBorder(). */
084  private static Border desktopIconBorder;
085
086  /** The shared instance for getRolloverButtonBorder(). */
087  private static Border toolbarButtonBorder;
088
089  /** The shared instance for getTextFieldBorder(). */
090  private static Border textFieldBorder;
091
092  /** The shared instance for getTextBorder(). */
093  private static Border textBorder;
094
095  /** The shared instance for getRolloverBorder(). */
096  private static Border rolloverBorder;
097
098  /**
099   * A MarginBorder that gets shared by multiple components.
100   * Created on demand by the private helper function {@link
101   * #getMarginBorder()}.
102   */
103  private static BasicBorders.MarginBorder marginBorder;
104
105  /**
106   * <p>A border used for {@link JButton} components.</p>
107   * 
108   * <p>This {@link Border} implementation can handle only instances of
109   * {@link AbstractButton} and their subclasses.</p>
110   * 
111   * <p>If the Metal Look and Feel's current theme is 'Ocean' the border
112   * will be painted with a special highlight when the mouse cursor if
113   * over the button (ie. the property <code>rollover</code> of the
114   * button's model is <code>true</code>) and is not a <b>direct</b>
115   * child of a {@link JToolBar}.</p> 
116   */
117  public static class ButtonBorder extends AbstractBorder implements UIResource
118  {
119    /** The borders insets. */
120    protected static Insets borderInsets = new Insets(3, 3, 3, 3);
121
122    /**
123     * Creates a new instance of <code>ButtonBorder</code>.
124     */
125    public ButtonBorder()
126    {
127      // Nothing to do here.
128    }
129
130    /**
131     * Paints the button border.
132     *
133     * @param c the component for which we paint the border
134     * @param g the Graphics context to use
135     * @param x the X coordinate of the upper left corner of c
136     * @param y the Y coordinate of the upper left corner of c
137     * @param w the width of c
138     * @param h the height of c
139     */
140    public void paintBorder(Component c, Graphics g, int x, int y, int w,
141                            int h)
142    {
143      // With the OceanTheme the button border is painted entirely different.
144      // However, I couldn't figure out how this is determined besides checking
145      // for instanceof OceanTheme. The button painting is definitely not
146      // influenced by a UI default property and it is definitely performed
147      // by the same Border class.
148      if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme)
149        paintOceanButtonBorder(c, g, x, y, w, h);
150      else
151        paintDefaultButtonBorder(c, g, x, y, w, h);
152    }
153
154    /**
155     * Paints the button border for the DefaultMetalTheme.
156     *
157     * @param c the component (button)
158     * @param g the graphics object to use
159     * @param x the upper left corner of the component, X coordinate
160     * @param y the upper left corner of the component, Y coordinate
161     * @param w the width of the component
162     * @param h the height of the component
163     */
164    private void paintDefaultButtonBorder(Component c, Graphics g, int x,
165                                          int y, int w, int h)
166    {
167      ButtonModel bmodel = null;
168
169      // The RI will fail with a ClassCastException in such a situation.
170      // This code tries to be more helpful.
171      if (c instanceof AbstractButton)
172        bmodel = ((AbstractButton) c).getModel();
173      else
174        throw new IllegalStateException("A ButtonBorder is supposed to work "
175                                        + "only with AbstractButton and"
176                                        + "subclasses.");
177
178      Color darkShadow = MetalLookAndFeel.getControlDarkShadow();
179      Color shadow = MetalLookAndFeel.getControlShadow();
180      Color light = MetalLookAndFeel.getControlHighlight();
181      Color middle = MetalLookAndFeel.getControl();
182
183      if (c.isEnabled())
184        {
185          // draw dark border
186          g.setColor(darkShadow);
187          g.drawRect(x, y, w - 2, h - 2);
188
189          // If the button is the default button, we paint a special border,
190          // regardless of the pressed state.
191          if (c instanceof JButton && ((JButton) c).isDefaultButton())
192            {
193              g.drawRect(x + 1, y + 1, w - 4, h - 4);
194              // Draw white highlight.
195              g.setColor(light);
196              g.drawLine(x + 2, y + 2, x + w - 4, y + 2);
197              g.drawLine(x + 2, y + 2, x + 2, y + h - 4);
198              g.drawLine(x + 2, y + h - 1, x + w - 1, y + h - 1);
199              g.drawLine(x + w - 1, y + 2, x + w - 1, y + h - 1);
200              // Draw crossing pixels.
201              g.setColor(middle);
202              g.fillRect(x + w - 2, y + 2, 1, 1);
203              g.fillRect(x + 2, y + h - 2, 1, 1);
204            }
205          else
206            {
207              // The normal border. This is used when the button is not
208              // pressed or the button is not armed.
209              if (! (bmodel.isPressed() && bmodel.isArmed()))
210                {
211                  // draw light border
212                  g.setColor(light);
213                  g.drawRect(x + 1, y + 1, w - 2, h - 2);
214
215                  // draw crossing pixels of both borders
216                  g.setColor(middle);
217                  g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2);
218                  g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1);
219                }
220              // The pressed border. This border is painted only when
221              // the button is both pressed and armed.
222              else
223                {
224                  // draw light border
225                  g.setColor(light);
226                  g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1);
227                  g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
228
229                  // draw shadow border
230                  g.setColor(middle);
231                  g.drawLine(x + 1, y + 1, x + w - 2, y + 1);
232                  g.drawLine(x + 1, y + 1, x + 1, y + h - 2);
233 
234                  // draw crossing pixels of both borders
235                  g.setColor(shadow);
236                  g.drawRect(x + 1, y + h - 2, 0, 0);
237                  g.drawRect(x + w - 2, y + 1, 0, 0);
238                }
239            }
240        }
241      else 
242        {
243          // draw disabled border
244          g.setColor(MetalLookAndFeel.getInactiveControlTextColor());
245          g.drawRect(x, y, w - 2, h - 2);          
246        }
247    }
248
249    /**
250     * Paints the button border for the OceanTheme.
251     *
252     * @param c the button
253     * @param g the graphics context
254     * @param x the X coordinate of the upper left corner of the painting rect
255     * @param y the Y coordinate of the upper left corner of the painting rect
256     * @param w the width of the painting rect
257     * @param h the height of the painting rect
258     */
259    private void paintOceanButtonBorder(Component c, Graphics g, int x,
260                                        int y, int w, int h)
261    {
262      ButtonModel bmodel = null;
263      
264      // The RI will fail with a ClassCastException in such a situation.
265      // This code tries to be more helpful.
266      if (c instanceof AbstractButton)
267        bmodel = ((AbstractButton) c).getModel();
268      else
269        throw new IllegalStateException("A ButtonBorder is supposed to work "
270                                        + "only with AbstractButton and"
271                                        + "subclasses.");
272
273      Color darkShadow = MetalLookAndFeel.getControlDarkShadow();
274      Color shadow = MetalLookAndFeel.getControlShadow();
275      Color light = MetalLookAndFeel.getControlHighlight();
276      Color middle = MetalLookAndFeel.getControl();
277
278      if (c.isEnabled())
279        {
280          // Paint the pressed border if the button is pressed, or if
281          // the button is the default button. In the OceanTheme, the default
282          // button has the same border as a pressed button.
283          if (bmodel.isPressed() || ((c instanceof JButton)
284                                     && ((JButton) c).isDefaultButton()))
285            {
286              // Draw fat border.
287              g.setColor(darkShadow);
288              g.drawRect(x, y, w - 1, h - 1);
289              g.drawRect(x + 1, y + 1, w - 3, h - 3);
290            }
291          else if (bmodel.isRollover() && !(c.getParent() instanceof JToolBar))
292            {
293              // Paint a bigger border when the mouse is over the button but
294              // only if it is *not* part of a JToolBar.
295              g.setColor(shadow);
296              g.drawRect(x, y, w - 1, h - 1);
297              g.drawRect(x + 2, y + 2, w - 5, h - 5);
298              g.setColor(darkShadow);
299              g.drawRect(x + 1, y + 1, w - 3, h - 3);
300            }
301          else
302            {
303              g.setColor(darkShadow);
304              g.drawRect(x, y, w - 1, h - 1);
305            }
306        }
307      else 
308        {
309          // draw disabled border
310          g.setColor(MetalLookAndFeel.getInactiveControlTextColor());
311          g.drawRect(x, y, w - 2, h - 2);          
312        }
313    }
314
315    /**
316     * Returns the insets of the <code>ButtonBorder</code>.
317     *
318     * @param c the component for which the border is used (ignored).
319     *
320     * @return The insets of the <code>ButtonBorder</code>.
321     */
322    public Insets getBorderInsets(Component c)
323    {
324      return borderInsets;
325    }
326
327    /**
328     * Returns the insets of the <code>ButtonBorder</code> in the specified 
329     * <code>newInsets</code> object.
330     *
331     * @param c the component for which the border is used (ignored).
332     * @param newInsets the insets object where to put the values (
333     *                  <code>null</code> not permitted).
334     *
335     * @return The <code>newInsets</code> reference.
336     */
337    public Insets getBorderInsets(Component c, Insets newInsets)
338    {
339      newInsets.bottom = borderInsets.bottom;
340      newInsets.left = borderInsets.left;
341      newInsets.right = borderInsets.right;
342      newInsets.top = borderInsets.top;
343      return newInsets;
344    }
345  }
346
347  /**
348   * A border used when painting {@link JInternalFrame} instances.
349   */
350  static class DesktopIconBorder extends AbstractBorder
351    implements UIResource
352  {
353    /**
354     * Creates a new border instance.
355     */
356    public DesktopIconBorder()
357    {
358      // Nothing to do here.
359    }
360    
361    /**
362     * Returns the border insets.
363     * 
364     * @param c  the component (ignored).
365     * 
366     * @return The border insets.
367     */
368    public Insets getBorderInsets(Component c)
369    {
370      return getBorderInsets(c, null);
371    }
372    
373    /**
374     * Returns the border insets.
375     * 
376     * @param c  the component (ignored).
377     * @return The border insets.
378     */
379    public Insets getBorderInsets(Component c, Insets newInsets)
380    {
381      if (newInsets == null)
382        newInsets = new Insets(3, 3, 2, 3);
383      else
384        {
385          newInsets.top = 3;
386          newInsets.left = 3;
387          newInsets.bottom = 2;
388          newInsets.right = 3;
389        }
390      return newInsets;  
391    }
392    
393    /**
394     * Paints the border for the specified component.
395     * 
396     * @param c  the component.
397     * @param g  the graphics device.
398     * @param x  the x-coordinate.
399     * @param y  the y-coordinate.
400     * @param w  the width.
401     * @param h  the height.
402     */
403    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
404        int h)
405    {
406      g.setColor(MetalLookAndFeel.getControlDarkShadow());      
407      g.drawRect(x, y, w - 1, h - 1); 
408    }
409    
410  }
411
412  /**
413   * A simple 3D border.
414   */
415  public static class Flush3DBorder extends AbstractBorder
416    implements UIResource
417  {
418    private static final Insets borderInsets = new Insets(2, 2, 2, 2);
419    
420    /**
421     * Creates a new border instance.
422     */
423    public Flush3DBorder()
424    {
425      // Nothing to do here.
426    }
427    
428    /**
429     * Returns the border insets.
430     * 
431     * @param c  the component (ignored).
432     * 
433     * @return The border insets.
434     */
435    public Insets getBorderInsets(Component c)
436    {
437      return borderInsets;
438    }
439    
440    /**
441     * Returns the border insets.
442     * 
443     * @param c  the component (ignored).
444     * @param newInsets  an existing insets instance, that will be populated
445     *                   with the border insets and returned as the result
446     *                   (<code>null</code> not permitted).
447     *                   
448     * @return The <code>newInsets</code> reference.
449     */
450    public Insets getBorderInsets(Component c, Insets newInsets)
451    {
452      newInsets.top = borderInsets.top;
453      newInsets.left = borderInsets.left;
454      newInsets.bottom = borderInsets.bottom;
455      newInsets.right = borderInsets.right;
456      return newInsets;  
457    }
458    
459    /**
460     * Paints the border for the specified component.
461     * 
462     * @param c  the component (ignored).
463     * @param g  the graphics device.
464     * @param x  the x-coordinate.
465     * @param y  the y-coordinate.
466     * @param w  the width.
467     * @param h  the height.
468     */
469    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
470        int h)
471    {              
472      Color savedColor = g.getColor();
473      g.setColor(MetalLookAndFeel.getControlDarkShadow());
474      g.drawRect(x, y, w - 2, h - 2);
475      g.setColor(MetalLookAndFeel.getControlHighlight());
476      g.drawRect(x + 1, y + 1, w - 2, h - 2);
477      g.setColor(MetalLookAndFeel.getControl());
478      g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2);
479      g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1);
480      g.setColor(savedColor);
481    }
482    
483  }
484    
485  /**
486   * A border used for a {@link JInternalFrame} when it is being used as a 
487   * palette.
488   * 
489   * @since 1.3
490   */
491  public static class PaletteBorder extends AbstractBorder
492    implements UIResource
493  {
494    private static final Insets borderInsets = new Insets(1, 1, 1, 1);
495
496    /**
497     * Creates a new <code>PaletteBorder</code>.
498     */
499    public PaletteBorder()
500    {
501      // Nothing to do here.
502    }
503    
504    /**
505     * Returns the border insets.
506     * 
507     * @param c  the component (ignored).
508     * 
509     * @return The border insets.
510     */
511    public Insets getBorderInsets(Component c)
512    {
513      return borderInsets;
514    }
515
516    /**
517     * Returns the border insets.
518     * 
519     * @param c  the component (ignored).
520     * @param newInsets  an existing insets instance, that will be populated
521     *                   with the border insets and returned as the result
522     *                   (<code>null</code> not permitted).
523     *                   
524     * @return The <code>newInsets</code> reference.
525     */
526    public Insets getBorderInsets(Component c, Insets newInsets)
527    {        
528      newInsets.top = borderInsets.top;
529      newInsets.left = borderInsets.left;
530      newInsets.bottom = borderInsets.bottom;
531      newInsets.right = borderInsets.right;
532      return newInsets;  
533    }
534    
535    /**
536     * Paints the border for the specified component.
537     * 
538     * @param c  the component (ignored).
539     * @param g  the graphics device.
540     * @param x  the x-coordinate.
541     * @param y  the y-coordinate.
542     * @param w  the width.
543     * @param h  the height.
544     */
545    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
546            int h)
547    {
548      Color savedColor = g.getColor();
549      
550      // draw the outline
551      g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
552      g.drawRect(x, y, w - 1, h - 1);
553      
554      // put a dot in each corner
555      g.setColor(MetalLookAndFeel.getControl());
556      g.fillRect(x, y, 1, 1);
557      g.fillRect(x + w - 1, y, 1, 1);
558      g.fillRect(x + w - 1, y + h - 1, 1, 1);
559      g.fillRect(x, y + h - 1, 1, 1);      
560      g.setColor(savedColor);
561    }
562
563  }
564    
565  /**
566   * A border used for the {@link JTextField} component.
567   */
568  public static class TextFieldBorder extends Flush3DBorder
569    implements UIResource
570  {
571    /**
572     * Creates a new border instance.
573     */
574    public TextFieldBorder()
575    {
576      // Nothing to do here.
577    }
578    
579    /**
580     * Paints the border for the specified component.
581     * 
582     * @param c  the component (ignored).
583     * @param g  the graphics device.
584     * @param x  the x-coordinate.
585     * @param y  the y-coordinate.
586     * @param w  the width.
587     * @param h  the height.
588     */
589    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
590        int h)
591    {
592      boolean enabledTextBorder;
593      if (c instanceof JTextComponent)
594        {
595          JTextComponent tc = (JTextComponent) c;
596          enabledTextBorder = tc.isEnabled() && tc.isEditable();
597        }
598      else
599        enabledTextBorder = false;
600
601      if (enabledTextBorder)
602        super.paintBorder(c, g, x, y, w, h);
603      else
604        {
605          Color savedColor = g.getColor();
606          g.setColor(MetalLookAndFeel.getControlShadow());
607          g.drawRect(x, y, w - 1, h - 1);
608          g.setColor(savedColor);
609        }
610    }
611    
612  }
613
614  /**
615   * A border used for the {@link JInternalFrame} component.
616   */
617  public static class InternalFrameBorder extends AbstractBorder
618    implements UIResource
619  {
620    private static final Insets borderInsets = new Insets(5, 5, 5, 5);
621
622    /**
623     * Creates a new border instance.
624     */
625    public InternalFrameBorder()
626    {
627      // Nothing to do here.
628    }
629    
630    /**
631     * Returns the border insets.
632     * 
633     * @param c  the component (ignored).
634     * 
635     * @return The border insets.
636     */
637    public Insets getBorderInsets(Component c)
638    {
639      return borderInsets;
640    }
641    
642    /**
643     * Returns the border insets.
644     * 
645     * @param c  the component (ignored).
646     * @param newInsets  an existing insets instance, that will be populated
647     *                   with the border insets and returned as the result
648     *                   (<code>null</code> not permitted).
649     *                   
650     * @return The <code>newInsets</code> reference.
651     */
652    public Insets getBorderInsets(Component c, Insets newInsets)
653    {
654      newInsets.top = borderInsets.top;
655      newInsets.left = borderInsets.left;
656      newInsets.bottom = borderInsets.bottom;
657      newInsets.right = borderInsets.right;
658      return newInsets;  
659    }
660    
661    /**
662     * Paints the border for the specified component.
663     * 
664     * @param c  the component.
665     * @param g  the graphics device.
666     * @param x  the x-coordinate.
667     * @param y  the y-coordinate.
668     * @param w  the width.
669     * @param h  the height.
670     */
671    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
672        int h)
673    {
674        
675      JInternalFrame f = (JInternalFrame) c;
676      if (f.isSelected())
677        g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
678      else
679        g.setColor(MetalLookAndFeel.getControlDarkShadow());
680      
681      // fill the border background
682      g.fillRect(x, y, w, 5);
683      g.fillRect(x, y, 5, h);
684      g.fillRect(x + w - 5, y, 5, h);
685      g.fillRect(x, y + h - 5, w, 5);
686      
687      // draw a dot in each corner
688      g.setColor(MetalLookAndFeel.getControl());
689      g.fillRect(x, y, 1, 1);
690      g.fillRect(x + w - 1, y, 1, 1);
691      g.fillRect(x + w - 1, y + h - 1, 1, 1);
692      g.fillRect(x, y + h - 1, 1, 1);
693      
694      // draw the lines
695      g.setColor(MetalLookAndFeel.getBlack());
696      g.drawLine(x + 14, y + 2, x + w - 15, y + 2);
697      g.drawLine(x + 14, y + h - 3, x + w - 15, y + h - 3);
698      g.drawLine(x + 2, y + 14, x + 2, y + h - 15);
699      g.drawLine(x + w - 3, y + 14, x + w - 3, y + h - 15);
700      
701      // draw the line highlights
702      if (f.isSelected())
703        g.setColor(MetalLookAndFeel.getPrimaryControlShadow());
704      else 
705        g.setColor(MetalLookAndFeel.getControlShadow());
706      g.drawLine(x + 15, y + 3, x + w - 14, y + 3);
707      g.drawLine(x + 15, y + h - 2, x + w - 14, y + h - 2);
708      g.drawLine(x + 3, y + 15, x + 3, y + h - 14);
709      g.drawLine(x + w - 2, y + 15, x + w - 2, y + h - 14);
710    }
711    
712  }
713
714  /**
715   * A border used for {@link JInternalFrame} components that are
716   * presented as dialogs (by the {@link JOptionPane} class).
717   */
718  public static class OptionDialogBorder extends AbstractBorder
719    implements UIResource
720  {
721      
722    /**
723     * Creates a new border instance.
724     */
725    public OptionDialogBorder()
726    {
727      // Nothing to do here.
728    }
729    
730    /**
731     * Returns the border insets.
732     * 
733     * @param c  the component (ignored).
734     * 
735     * @return The border insets.
736     */
737    public Insets getBorderInsets(Component c)
738    {
739      return getBorderInsets(c, null);
740    }
741    
742    /**
743     * Returns the border insets.
744     * 
745     * @param c  the component (ignored).
746     * @return The border insets.
747     */
748    public Insets getBorderInsets(Component c, Insets newInsets)
749    {
750      if (newInsets == null)
751        newInsets = new Insets(3, 3, 3, 3);
752      else
753        {
754          newInsets.top = 3;
755          newInsets.left = 3;
756          newInsets.bottom = 3;
757          newInsets.right = 3;
758        }
759      return newInsets;  
760    }
761        
762    /**
763     * Paints the border for the specified component.
764     * 
765     * @param c  the component.
766     * @param g  the graphics device.
767     * @param x  the x-coordinate.
768     * @param y  the y-coordinate.
769     * @param w  the width.
770     * @param h  the height.
771     */
772    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
773        int h)
774    {
775        
776      JInternalFrame f = (JInternalFrame) c;
777      g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
778      if (f.getContentPane() instanceof JOptionPane)
779        {
780          JOptionPane pane = (JOptionPane) f.getContentPane();
781          int type = pane.getMessageType();
782          if (type == JOptionPane.QUESTION_MESSAGE)
783            {
784              Color bc = UIManager.getColor(
785                  "OptionPane.questionDialog.border.background");
786              if (bc != null)
787                g.setColor(bc);
788            }
789          if (type == JOptionPane.WARNING_MESSAGE)
790            {
791              Color bc = UIManager.getColor(
792                  "OptionPane.warningDialog.border.background");
793              if (bc != null)
794                g.setColor(bc);              
795            }
796          else if (type == JOptionPane.ERROR_MESSAGE)
797            {
798              Color bc = UIManager.getColor(
799                  "OptionPane.errorDialog.border.background");
800              if (bc != null)
801                g.setColor(bc);              
802            }
803        }
804      
805      // fill the border background
806      g.fillRect(x, y, w, 3);
807      g.fillRect(x, y, 3, h);
808      g.fillRect(x + w - 3, y, 3, h);
809      g.fillRect(x, y + h - 3, w, 3);
810      
811      // draw a dot in each corner
812      g.setColor(MetalLookAndFeel.getControl());
813      g.fillRect(x, y, 1, 1);
814      g.fillRect(x + w - 1, y, 1, 1);
815      g.fillRect(x + w - 1, y + h - 1, 1, 1);
816      g.fillRect(x, y + h - 1, 1, 1);
817      
818    }
819    
820  }
821
822  /**
823   * A border used for {@link JMenu} and {@link JMenuItem} components.
824   */
825  public static class MenuItemBorder extends AbstractBorder
826    implements UIResource
827  {
828    /** The border insets. */
829    protected static Insets borderInsets = new Insets(2, 2, 2, 2);
830    
831    /**
832     * Creates a new border instance.
833     */
834    public MenuItemBorder()
835    {
836      // Nothing to do here.
837    }
838    
839    /**
840     * Paints the border for the component.  A border is painted only if the
841     * component is a selected {@link JMenu} or an armed {@link JMenuItem}.
842     * 
843     * @param c  the component.
844     * @param g  the graphics device.
845     * @param x  the x-coordinate of the border area.
846     * @param y  the y-coordinate of the border area.
847     * @param w  the width of the border area.
848     * @param h  the height of the border area.
849     */
850    public void paintBorder(Component c, Graphics g, int x, int y, int w,
851        int h)
852    {
853      Color dark = MetalLookAndFeel.getPrimaryControlDarkShadow();
854      Color light = MetalLookAndFeel.getPrimaryControlHighlight();
855      if (c instanceof JMenu) 
856        {
857          JMenu menu = (JMenu) c;
858          if (menu.isSelected())
859            {
860              g.setColor(dark);
861              g.drawLine(x, y, x, y + h);
862              g.drawLine(x, y, x + w, y);
863              g.drawLine(x + w - 2, y + 1, x + w - 2, y + h);
864              g.setColor(light);
865              g.drawLine(x + w - 1, y + 1, x + w - 1, y + h);
866            }
867        }
868      else if (c instanceof JMenuItem)
869        {
870          JMenuItem item = (JMenuItem) c;
871          if (item.isArmed()) 
872            {
873              g.setColor(dark);
874              g.drawLine(x, y, x + w, y);
875              g.setColor(light);
876              g.drawLine(x, y + h - 1, x + w, y + h - 1);
877            }
878          else
879            {
880              // Normally we draw a light line on the left.
881              g.setColor(light);
882              g.drawLine(x, y, x, y + h);
883            }
884        }
885    }
886    
887    /**
888     * Returns the border insets.
889     * 
890     * @param c  the component (ignored).
891     * 
892     * @return The border insets.
893     */
894    public Insets getBorderInsets(Component c)
895    {
896      return borderInsets;
897    }
898    
899    /**
900     * Populates <code>insets</code> with the border insets, then returns it.
901     * 
902     * @param c  the component (ignored).
903     * @param insets  the object to populate with the border insets.
904     * 
905     * @return The border insets.
906     * 
907     * @throws NullPointerException if <code>insets</code> is <code>null</code>.
908     */
909    public Insets getBorderInsets(Component c, Insets insets)
910    {
911      insets.left = borderInsets.left;
912      insets.top = borderInsets.top;
913      insets.bottom = borderInsets.bottom;
914      insets.right = borderInsets.right;
915      return insets;
916    }
917  }
918
919  /**
920   * A border used for {@link JMenuBar} components.
921   */
922  public static class MenuBarBorder
923      extends AbstractBorder
924      implements UIResource
925  {
926    /** The border insets. */
927    protected static Insets borderInsets = new Insets(1, 0, 1, 0);
928    
929    /**
930     * Creates a new border instance.
931     */
932    public MenuBarBorder()
933    {
934    }
935    
936    /**
937     * Paints the border for the component.  A border is painted only if the
938     * component is a selected {@link JMenu} or an armed {@link JMenuItem}.
939     * 
940     * @param c  the component.
941     * @param g  the graphics device.
942     * @param x  the x-coordinate of the border area.
943     * @param y  the y-coordinate of the border area.
944     * @param w  the width of the border area.
945     * @param h  the height of the border area.
946     */
947    public void paintBorder(Component c, Graphics g, int x, int y, int w,
948        int h)
949    {
950      // Although it is not correct to decide on the static property
951      // currentTheme which color to use the RI does it like that.
952      // The trouble is that by simply changing the current theme to
953      // e.g. DefaultMetalLookAndFeel this method will use another color
954      // although a change in painting behavior should be expected only
955      // after setting a new look and feel and updating all components.
956      if(MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme)
957        g.setColor(UIManager.getColor("MenuBar.borderColor"));
958      else
959        g.setColor(MetalLookAndFeel.getControlShadow());
960      
961      g.drawLine(x, y + h - 1, x + w, y + h - 1);
962    }
963    
964    /**
965     * Returns the border insets.
966     * 
967     * @param c  the component (ignored).
968     * 
969     * @return The border insets.
970     */
971    public Insets getBorderInsets(Component c)
972    {
973      return borderInsets;
974    }
975    
976    /**
977     * Populates <code>insets</code> with the border insets, then returns it.
978     * 
979     * @param c  the component (ignored).
980     * @param insets  the object to populate with the border insets.
981     * 
982     * @return The border insets.
983     * 
984     * @throws NullPointerException if <code>insets</code> is <code>null</code>.
985     */
986    public Insets getBorderInsets(Component c, Insets insets)
987    {
988      insets.left = borderInsets.left;
989      insets.top = borderInsets.top;
990      insets.bottom = borderInsets.bottom;
991      insets.right = borderInsets.right;
992      return insets;
993    }
994  }
995
996  /**
997   * A border for {@link JScrollPane} components.
998   */
999  public static class ScrollPaneBorder
1000    extends AbstractBorder
1001    implements UIResource
1002  {
1003    /** The border insets. */
1004    private static Insets insets = new Insets(1, 1, 2, 2);
1005    
1006    /**
1007     * Constructs a new ScrollPaneBorder.
1008     */
1009    public ScrollPaneBorder()
1010    {
1011      // Nothing to do here.
1012    }
1013    
1014    /**
1015     * Returns the insets of the border for the Component <code>c</code>.
1016     *
1017     * @param c the Component for which we return the border insets
1018     */
1019    public Insets getBorderInsets(Component c)
1020    {
1021      return insets;
1022    }
1023
1024    /**
1025     * Paints the border.
1026     *
1027     * @param c the Component for which the border is painted
1028     * @param g the Graphics context
1029     * @param x the X coordinate of the upper left corner of the border
1030     * @param y the Y coordinate of the upper left corner of the border
1031     * @param w the width of the border
1032     * @param h the height of the border
1033     */
1034    public void paintBorder(Component c, Graphics g, int x, int y,
1035                            int w, int h)
1036    {
1037      Color darkShadow = MetalLookAndFeel.getControlDarkShadow();
1038      Color shadow = MetalLookAndFeel.getControlShadow();
1039      Color light = MetalLookAndFeel.getWhite();
1040      Color middle = MetalLookAndFeel.getControl();
1041
1042      // paint top border line
1043      g.setColor(darkShadow);
1044      g.drawLine(x, y, x + w - 2, y);
1045
1046      // paint left border line
1047      g.drawLine(x, y, x, y + h - 2);
1048 
1049      // paint right inner border line
1050      g.drawLine(x + w - 2, y, x + w - 2, y + h + 1);
1051
1052      // paint bottom inner border line
1053      g.drawLine(x + 2, y + h - 2, x + w - 2, y + h - 2);
1054
1055      // draw right outer border line
1056      g.setColor(light);
1057      g.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
1058
1059      // draw bottom outer border line
1060      g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
1061
1062      // paint the lighter points
1063      g.setColor(middle);
1064      g.drawLine(x + w - 1, y, x + w - 1, y);
1065      g.drawLine(x + w - 2, y + 2, x + w - 2, y + 2);
1066      g.drawLine(x, y + h - 1, x, y + h - 1);
1067      g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2);
1068
1069    }
1070    
1071  }
1072  
1073  /**
1074   * A button border that is only visible when the mouse pointer is within 
1075   * the button's bounds.
1076   */
1077  public static class RolloverButtonBorder
1078    extends MetalBorders.ButtonBorder
1079  {
1080    /**
1081     * Creates a new border instance.
1082     */
1083    public RolloverButtonBorder()
1084    {
1085      // Nothing to do here.
1086    }
1087    
1088    /**
1089     * Paints the border.
1090     * 
1091     * @param c  the component.
1092     * @param g  the graphics device.
1093     * @param x  the x-coordinate.
1094     * @param y  the y-coordinate.
1095     * @param w  the width.
1096     * @param h  the height.
1097     */
1098    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
1099            int h)
1100    {
1101      // TODO: What should be done here? Obviously the ButtonBorder already
1102      // handles the rollover state in Sun's impl. Maybe this is only there
1103      // for backwards compatibility.
1104      super.paintBorder(c, g, x, y, w, h);
1105    }
1106  }
1107  
1108  /**
1109   * This border is used in Toolbar buttons as inner border.
1110   */
1111  static class RolloverMarginBorder extends AbstractBorder
1112  {
1113    /** The borders insets. */
1114    protected static Insets borderInsets = new Insets(3, 3, 3, 3);
1115
1116    /**
1117     * Creates a new instance of RolloverBorder.
1118     */
1119    public RolloverMarginBorder()
1120    {
1121      // Nothing to do here.
1122    }
1123    
1124    /**
1125     * Returns the insets of the RolloverBorder.
1126     *
1127     * @param c the component for which the border is used
1128     *
1129     * @return the insets of the RolloverBorder
1130     */
1131    public Insets getBorderInsets(Component c)
1132    {
1133      return getBorderInsets(c, null);
1134    }
1135
1136    /**
1137     * Returns the insets of the RolloverMarginBorder in the specified
1138     * Insets object.
1139     *
1140     * @param c the component for which the border is used
1141     * @param newInsets the insets object where to put the values
1142     *
1143     * @return the insets of the RolloverMarginBorder
1144     */
1145    public Insets getBorderInsets(Component c, Insets newInsets)
1146    {
1147      if (newInsets == null)
1148        newInsets = new Insets(0, 0, 0, 0);
1149
1150      AbstractButton b = (AbstractButton) c;
1151      Insets margin = b.getMargin();
1152      newInsets.bottom = borderInsets.bottom;
1153      newInsets.left = borderInsets.left;
1154      newInsets.right = borderInsets.right;
1155      newInsets.top = borderInsets.top;
1156      return newInsets;
1157    }
1158  }
1159
1160  /**
1161   * A border implementation for popup menus.
1162   */
1163  public static class PopupMenuBorder
1164    extends AbstractBorder
1165    implements UIResource
1166  {
1167
1168    /** The border's insets. */
1169    protected static Insets borderInsets = new Insets(3, 1, 2, 1);
1170
1171    /**
1172     * Constructs a new PopupMenuBorder.
1173     */
1174    public PopupMenuBorder()
1175    {
1176      // Nothing to do here.
1177    }
1178    
1179    /**
1180     * Returns the insets of the border, creating a new Insets instance
1181     * with each call.
1182     *
1183     * @param c the component for which we return the border insets
1184     *          (not used here)
1185     */
1186    public Insets getBorderInsets(Component c)
1187    {
1188      return getBorderInsets(c, null);
1189    }
1190    
1191    /**
1192     * Returns the insets of the border, using the supplied Insets instance.
1193     *
1194     * @param c the component for which we return the border insets
1195     *          (not used here)
1196     * @param i the Insets instance to fill with the Insets values
1197     */
1198    public Insets getBorderInsets(Component c, Insets i)
1199    {
1200      Insets insets;
1201      if (i == null)
1202        insets = new Insets(borderInsets.top, borderInsets.left,
1203                            borderInsets.bottom, borderInsets.right);
1204      else
1205        {
1206          insets = i;
1207          insets.top = borderInsets.top;
1208          insets.left = borderInsets.left;
1209          insets.bottom = borderInsets.bottom;
1210          insets.right = borderInsets.right;
1211        }
1212      
1213      return insets;
1214    }
1215
1216    /**
1217     * Paints the border for component <code>c</code> using the
1218     * Graphics context <code>g</code> with the dimension
1219     * <code>x, y, w, h</code>.
1220     *
1221     * @param c the component for which we paint the border
1222     * @param g the Graphics context to use
1223     * @param x the X coordinate of the upper left corner of c
1224     * @param y the Y coordinate of the upper left corner of c
1225     * @param w the width of c
1226     * @param h the height of c
1227     */
1228    public void paintBorder(Component c, Graphics g, int x, int y, int w,
1229                            int h)
1230    {
1231      Color darkShadow = MetalLookAndFeel.getPrimaryControlDarkShadow();
1232      Color light = MetalLookAndFeel.getPrimaryControlHighlight();
1233
1234      // draw dark outer border
1235      g.setColor(darkShadow);
1236      g.drawRect(x, y, w - 1, h - 1);
1237      
1238      // draw highlighted inner border (only top and left)
1239      g.setColor(light);
1240      g.drawLine(x + 1, y + 1, x + w - 2, y + 1);
1241    }
1242    
1243  }
1244
1245  /**
1246   * A border used for the {@link JToggleButton} component.
1247   * 
1248   * @since 1.3
1249   */
1250  public static class ToggleButtonBorder
1251    extends ButtonBorder 
1252  {
1253    /**
1254     * Creates a new border instance.
1255     */
1256    public ToggleButtonBorder()
1257    {
1258      // Nothing to do here.
1259    }
1260    
1261    /**
1262     * Paints the toggle button border.
1263     *
1264     * @param c the component for which we paint the border
1265     * @param g the Graphics context to use
1266     * @param x the X coordinate of the upper left corner of c
1267     * @param y the Y coordinate of the upper left corner of c
1268     * @param w the width of c
1269     * @param h the height of c
1270     */
1271    public void paintBorder(Component c, Graphics g, int x, int y, int w,
1272                            int h)
1273    {
1274      ButtonModel bmodel = null;
1275      
1276      if (c instanceof AbstractButton)
1277        bmodel = ((AbstractButton) c).getModel();
1278
1279      Color darkShadow = MetalLookAndFeel.getControlDarkShadow();
1280      Color shadow = MetalLookAndFeel.getControlShadow();
1281      Color light = MetalLookAndFeel.getWhite();
1282      Color middle = MetalLookAndFeel.getControl();
1283
1284      if (c.isEnabled())
1285        {
1286          // draw dark border
1287          g.setColor(darkShadow);
1288          g.drawRect(x, y, w - 2, h - 2);
1289
1290          if (!bmodel.isArmed())
1291            {
1292              // draw light border
1293              g.setColor(light);
1294              g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
1295              g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1);
1296              if (bmodel.isSelected())
1297                g.setColor(middle);
1298              g.drawLine(x + 1, y + 1, x + w - 3, y + 1);
1299              g.drawLine(x + 1, y + 1, x + 1, y + h - 3);
1300
1301              // draw crossing pixels of both borders
1302              g.setColor(shadow);
1303              g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2);
1304              g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1);
1305            }
1306          else
1307            {
1308              // draw light border
1309              g.setColor(light);
1310              g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1);
1311              g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
1312
1313              // draw shadow border
1314              g.setColor(shadow);
1315              g.drawLine(x + 1, y + 1, x + w - 2, y + 1);
1316              g.drawLine(x + 1, y + 1, x + 1, y + h - 2);
1317 
1318              // draw crossing pixels of both borders
1319              g.setColor(shadow);
1320              g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2);
1321              g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1);
1322              
1323            }
1324          // draw corners
1325          g.setColor(middle);
1326          g.drawLine(x, y + h - 1, x, y + h - 1);
1327          g.drawLine(x + w - 1, y, x + w - 1, y);
1328        }
1329      else 
1330        {
1331          // draw disabled border
1332          g.setColor(MetalLookAndFeel.getControlDisabled());
1333          g.drawRect(x, y, w - 2, h - 2);          
1334        }
1335    }
1336  }
1337
1338  /**
1339   * A border used for the {@link JToolBar} component.
1340   */
1341  public static class ToolBarBorder extends AbstractBorder
1342    implements UIResource, SwingConstants
1343  {
1344    /**
1345     * Creates a new border instance.
1346     */
1347    public ToolBarBorder()
1348    {
1349      // Nothing to do here.
1350    }
1351    
1352    /**
1353     * Returns the border insets.
1354     * 
1355     * @param c  the component (ignored).
1356     * 
1357     * @return The border insets.
1358     */
1359    public Insets getBorderInsets(Component c)
1360    {
1361      return getBorderInsets(c, null);
1362    }
1363    
1364    /**
1365     * Returns the border insets.
1366     * 
1367     * @param c  the component (ignored).
1368     * @return The border insets.
1369     */
1370    public Insets getBorderInsets(Component c, Insets newInsets)
1371    {
1372      JToolBar tb = (JToolBar) c;
1373      if (tb.getOrientation() == JToolBar.HORIZONTAL)
1374        {   
1375          if (newInsets == null)
1376            newInsets = new Insets(2, 16, 2, 2);
1377          else
1378            {
1379              newInsets.top = 2;
1380              newInsets.left = 16;
1381              newInsets.bottom = 2;
1382              newInsets.right = 2;
1383            }
1384          return newInsets;  
1385        }
1386      else // assume JToolBar.VERTICAL
1387        { 
1388          if (newInsets == null)
1389            newInsets = new Insets(16, 2, 2, 2);
1390          else
1391            {
1392              newInsets.top = 16;
1393              newInsets.left = 2;
1394              newInsets.bottom = 2;
1395              newInsets.right = 2;
1396            }
1397          return newInsets;  
1398        }
1399
1400    }
1401    
1402    /**
1403     * Paints the border for the specified component.
1404     * 
1405     * @param c  the component.
1406     * @param g  the graphics device.
1407     * @param x  the x-coordinate.
1408     * @param y  the y-coordinate.
1409     * @param w  the width.
1410     * @param h  the height.
1411     */
1412    public void paintBorder(Component c, Graphics g, int x, int y, int w, 
1413        int h)
1414    {
1415        
1416      JToolBar tb = (JToolBar) c;
1417      if (tb.getOrientation() == JToolBar.HORIZONTAL)
1418        {
1419           MetalUtils.fillMetalPattern(tb, g, x + 2, y + 2, x + 11, y + h - 5, 
1420                  MetalLookAndFeel.getControlHighlight(), 
1421                  MetalLookAndFeel.getControlDarkShadow());
1422        }
1423      else
1424        { 
1425          MetalUtils.fillMetalPattern(tb, g, x + 2, y + 2, x + w - 5, y + 11, 
1426                  MetalLookAndFeel.getControlHighlight(), 
1427                  MetalLookAndFeel.getControlDarkShadow());
1428        }
1429    }
1430    
1431  }
1432  
1433  /**
1434   * A border for table header cells.
1435   *
1436   * @since 1.3
1437   */
1438  public static class TableHeaderBorder extends AbstractBorder
1439  {
1440    /**
1441     * The insets of this border.
1442     */
1443    // TODO: According to tests that I have done, this is really the border
1444    // that should be returned by getBorderInsets(). However, the name
1445    // is very distracting. Is there any deeper meaning in it?
1446    protected Insets editorBorderInsets;
1447
1448    /**
1449     * Creates a new instance of <code>TableHeaderBorder</code>.
1450     */
1451    public TableHeaderBorder()
1452    {
1453      editorBorderInsets = new Insets(1, 1, 1, 1);
1454    }
1455
1456    /**
1457     * Return the insets of this border.
1458     *
1459     * @return the insets of this border
1460     */
1461    public Insets getBorderInsets(Component c)
1462    {
1463      return editorBorderInsets;
1464    }
1465
1466    /**
1467     * Paints the border.
1468     *
1469     * @param c the component for which to paint the border
1470     * @param g the graphics context to use
1471     * @param x the x cooridinate of the border rectangle
1472     * @param y the y cooridinate of the border rectangle
1473     * @param w the width of the border rectangle
1474     * @param h the height of the border rectangle
1475     */
1476    public void paintBorder(Component c, Graphics g, int x, int y, int w, int h)
1477    {
1478      Color dark = MetalLookAndFeel.getControlDarkShadow();
1479      Color light = MetalLookAndFeel.getWhite();
1480      Color old = g.getColor();
1481      g.setColor(light);
1482      g.drawLine(x, y, x + w - 2, y);
1483      g.drawLine(x, y, x, y + h - 2);
1484      g.setColor(dark);
1485      g.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
1486      g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
1487      g.setColor(old);
1488    }
1489  }
1490
1491  /**
1492   * Returns a border for Swing buttons in the Metal Look &amp; Feel.
1493   *
1494   * @return a border for Swing buttons in the Metal Look &amp; Feel
1495   */
1496  public static Border getButtonBorder()
1497  {
1498    if (buttonBorder == null)
1499      {
1500        Border outer = new ButtonBorder();
1501        Border inner = getMarginBorder();
1502        buttonBorder = new BorderUIResource.CompoundBorderUIResource(outer, 
1503            inner);
1504      }
1505    return buttonBorder;
1506  }
1507  
1508  /**
1509   * Returns a border for use with {@link JToggleButton} components.
1510   *
1511   * @return A border.
1512   * 
1513   * @since 1.3
1514   */
1515  public static Border getToggleButtonBorder()
1516  {
1517    if (toggleButtonBorder == null)
1518      {
1519        Border outer = new ToggleButtonBorder();
1520        Border inner = getMarginBorder();
1521        toggleButtonBorder = new BorderUIResource.CompoundBorderUIResource(
1522            outer, inner);
1523      }
1524    return toggleButtonBorder;
1525  }
1526
1527  /**
1528   * Returns a border instance that is used with a {@link JInternalFrame} when
1529   * it is in the iconified state.
1530   * 
1531   * @return A border.
1532   * 
1533   * @since 1.3
1534   */
1535  public static Border getDesktopIconBorder()
1536  {
1537    if (desktopIconBorder == null)
1538      desktopIconBorder = new DesktopIconBorder();
1539    return desktopIconBorder;      
1540  }
1541
1542  /**
1543   * Returns a border for use by the {@link JTextField} component.
1544   * 
1545   * @return A border.
1546   * 
1547   * @since 1.3
1548   */
1549  public static Border getTextFieldBorder()
1550  {
1551    if (textFieldBorder == null)
1552      {
1553        Border inner = getMarginBorder();
1554        Border outer = new TextFieldBorder();
1555        textFieldBorder =
1556          new BorderUIResource.CompoundBorderUIResource(outer, inner);
1557      }
1558    return textFieldBorder;
1559  }
1560
1561  /**
1562   * Returns the border that is used for text components (except text fields,
1563   * which use {@link #getTextFieldBorder}.
1564   *
1565   * @return the border that is used for text components
1566   *
1567   * @since 1.3
1568   */
1569  public static Border getTextBorder()
1570  {
1571    if (textBorder == null)
1572      {
1573        Border inner = getMarginBorder();
1574        Border outer = new Flush3DBorder();
1575        textBorder =
1576          new BorderUIResource.CompoundBorderUIResource(outer, inner);
1577      }
1578    return textBorder;
1579  }
1580
1581  /**
1582   * Returns a border for Toolbar buttons in the Metal Look &amp; Feel.
1583   *
1584   * @return a border for Toolbar buttons in the Metal Look &amp; Feel
1585   */
1586  static Border getToolbarButtonBorder()
1587  {
1588    if (toolbarButtonBorder == null)
1589      {
1590        Border outer = new ButtonBorder();
1591        Border inner = new RolloverMarginBorder();
1592        toolbarButtonBorder = new CompoundBorder(outer, inner);
1593      }
1594    return toolbarButtonBorder;
1595  }
1596
1597  /**
1598   * Returns a shared instance of {@link BasicBorders.MarginBorder}.
1599   *
1600   * @return a shared instance of {@link BasicBorders.MarginBorder}
1601   */
1602  static Border getMarginBorder()
1603  {
1604    if (marginBorder == null)
1605      marginBorder = new BasicBorders.MarginBorder();
1606    return marginBorder;
1607  }
1608
1609  /**
1610   * Returns a shared instance of a compound border for rollover buttons.
1611   * 
1612   * @return A shared border instance.
1613   */
1614  static Border getRolloverBorder()
1615  {
1616    if (rolloverBorder == null)
1617      {
1618        Border outer = new MetalBorders.RolloverButtonBorder();
1619        Border inner = MetalBorders.getMarginBorder();
1620        rolloverBorder = new BorderUIResource.CompoundBorderUIResource(outer, 
1621            inner);
1622      }
1623    return rolloverBorder;
1624  }
1625
1626}