001    /* MetalBorders.java
002       Copyright (C) 2005, 2006, Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package javax.swing.plaf.metal;
040    
041    import java.awt.Color;
042    import java.awt.Component;
043    import java.awt.Graphics;
044    import java.awt.Insets;
045    
046    import javax.swing.AbstractButton;
047    import javax.swing.ButtonModel;
048    import javax.swing.JButton;
049    import javax.swing.JInternalFrame;
050    import javax.swing.JMenu;
051    import javax.swing.JMenuBar;
052    import javax.swing.JMenuItem;
053    import javax.swing.JOptionPane;
054    import javax.swing.JScrollPane;
055    import javax.swing.JTextField;
056    import javax.swing.JToggleButton;
057    import javax.swing.JToolBar;
058    import javax.swing.SwingConstants;
059    import javax.swing.UIManager;
060    import javax.swing.border.AbstractBorder;
061    import javax.swing.border.Border;
062    import javax.swing.border.CompoundBorder;
063    import javax.swing.plaf.BorderUIResource;
064    import javax.swing.plaf.UIResource;
065    import javax.swing.plaf.basic.BasicBorders;
066    import 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     */
074    public 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    }