1 /*
   2  * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.swing.plaf.metal;
  27 
  28 import javax.swing.*;
  29 import javax.swing.border.*;
  30 import javax.swing.plaf.*;
  31 import javax.swing.plaf.basic.BasicBorders;
  32 import javax.swing.text.JTextComponent;
  33 
  34 import java.awt.Component;
  35 import java.awt.Insets;
  36 import java.awt.Color;
  37 import java.awt.Dialog;
  38 import java.awt.Frame;
  39 import java.awt.Graphics;
  40 import java.awt.Window;
  41 
  42 import sun.swing.StringUIClientPropertyKey;
  43 
  44 
  45 /**
  46  * Factory object that can vend Borders appropriate for the metal L & F.
  47  * @author Steve Wilson
  48  */
  49 
  50 public class MetalBorders {
  51 
  52     /**
  53      * Client property indicating the button shouldn't provide a rollover
  54      * indicator. Only used with the Ocean theme.
  55      */
  56     static Object NO_BUTTON_ROLLOVER =
  57         new StringUIClientPropertyKey("NoButtonRollover");
  58 
  59     @SuppressWarnings("serial") // Superclass is not serializable across versions
  60     public static class Flush3DBorder extends AbstractBorder implements UIResource{
  61         public void paintBorder(Component c, Graphics g, int x, int y,
  62                           int w, int h) {
  63             if (c.isEnabled()) {
  64                 MetalUtils.drawFlush3DBorder(g, x, y, w, h);
  65             } else {
  66                 MetalUtils.drawDisabledBorder(g, x, y, w, h);
  67             }
  68         }
  69 
  70         public Insets getBorderInsets(Component c, Insets newInsets) {
  71             newInsets.set(2, 2, 2, 2);
  72             return newInsets;
  73         }
  74     }
  75 
  76     @SuppressWarnings("serial") // Superclass is not serializable across versions
  77     public static class ButtonBorder extends AbstractBorder implements UIResource {
  78 
  79         protected static Insets borderInsets = new Insets( 3, 3, 3, 3 );
  80 
  81         public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
  82             if (!(c instanceof AbstractButton)) {
  83                 return;
  84             }
  85             if (MetalLookAndFeel.usingOcean()) {
  86                 paintOceanBorder(c, g, x, y, w, h);
  87                 return;
  88             }
  89             AbstractButton button = (AbstractButton)c;
  90             ButtonModel model = button.getModel();
  91 
  92             if ( model.isEnabled() ) {
  93                 boolean isPressed = model.isPressed() && model.isArmed();
  94                 boolean isDefault = (button instanceof JButton && ((JButton)button).isDefaultButton());
  95 
  96                 if (isPressed && isDefault) {
  97                     MetalUtils.drawDefaultButtonPressedBorder(g, x, y, w, h);
  98                 } else if (isPressed) {
  99                     MetalUtils.drawPressed3DBorder( g, x, y, w, h );
 100                 } else if (isDefault) {
 101                     MetalUtils.drawDefaultButtonBorder( g, x, y, w, h, false);
 102                 } else {
 103                     MetalUtils.drawButtonBorder( g, x, y, w, h, false);
 104                 }
 105             } else { // disabled state
 106                 MetalUtils.drawDisabledBorder( g, x, y, w-1, h-1 );
 107             }
 108         }
 109 
 110         private void paintOceanBorder(Component c, Graphics g, int x, int y,
 111                                       int w, int h) {
 112             AbstractButton button = (AbstractButton)c;
 113             ButtonModel model = ((AbstractButton)c).getModel();
 114 
 115             g.translate(x, y);
 116             if (MetalUtils.isToolBarButton(button)) {
 117                 if (model.isEnabled()) {
 118                     if (model.isPressed()) {
 119                         g.setColor(MetalLookAndFeel.getWhite());
 120                         g.fillRect(1, h - 1, w - 1, 1);
 121                         g.fillRect(w - 1, 1, 1, h - 1);
 122                         g.setColor(MetalLookAndFeel.getControlDarkShadow());
 123                         g.drawRect(0, 0, w - 2, h - 2);
 124                         g.fillRect(1, 1, w - 3, 1);
 125                     }
 126                     else if (model.isSelected() || model.isRollover()) {
 127                         g.setColor(MetalLookAndFeel.getWhite());
 128                         g.fillRect(1, h - 1, w - 1, 1);
 129                         g.fillRect(w - 1, 1, 1, h - 1);
 130                         g.setColor(MetalLookAndFeel.getControlDarkShadow());
 131                         g.drawRect(0, 0, w - 2, h - 2);
 132                     }
 133                     else {
 134                         g.setColor(MetalLookAndFeel.getWhite());
 135                         g.drawRect(1, 1, w - 2, h - 2);
 136                         g.setColor(UIManager.getColor(
 137                                 "Button.toolBarBorderBackground"));
 138                         g.drawRect(0, 0, w - 2, h - 2);
 139                     }
 140                 }
 141                 else {
 142                    g.setColor(UIManager.getColor(
 143                            "Button.disabledToolBarBorderBackground"));
 144                    g.drawRect(0, 0, w - 2, h - 2);
 145                 }
 146             }
 147             else if (model.isEnabled()) {
 148                 boolean pressed = model.isPressed();
 149                 boolean armed = model.isArmed();
 150 
 151                 if ((c instanceof JButton) && ((JButton)c).isDefaultButton()) {
 152                     g.setColor(MetalLookAndFeel.getControlDarkShadow());
 153                     g.drawRect(0, 0, w - 1, h - 1);
 154                     g.drawRect(1, 1, w - 3, h - 3);
 155                 }
 156                 else if (pressed) {
 157                     g.setColor(MetalLookAndFeel.getControlDarkShadow());
 158                     g.fillRect(0, 0, w, 2);
 159                     g.fillRect(0, 2, 2, h - 2);
 160                     g.fillRect(w - 1, 1, 1, h - 1);
 161                     g.fillRect(1, h - 1, w - 2, 1);
 162                 }
 163                 else if (model.isRollover() && button.getClientProperty(
 164                                NO_BUTTON_ROLLOVER) == null) {
 165                     g.setColor(MetalLookAndFeel.getPrimaryControl());
 166                     g.drawRect(0, 0, w - 1, h - 1);
 167                     g.drawRect(2, 2, w - 5, h - 5);
 168                     g.setColor(MetalLookAndFeel.getControlDarkShadow());
 169                     g.drawRect(1, 1, w - 3, h - 3);
 170                 }
 171                 else {
 172                     g.setColor(MetalLookAndFeel.getControlDarkShadow());
 173                     g.drawRect(0, 0, w - 1, h - 1);
 174                 }
 175             }
 176             else {
 177                 g.setColor(MetalLookAndFeel.getInactiveControlTextColor());
 178                 g.drawRect(0, 0, w - 1, h - 1);
 179                 if ((c instanceof JButton) && ((JButton)c).isDefaultButton()) {
 180                     g.drawRect(1, 1, w - 3, h - 3);
 181                 }
 182             }
 183         }
 184 
 185         public Insets getBorderInsets(Component c, Insets newInsets) {
 186             newInsets.set(3, 3, 3, 3);
 187             return newInsets;
 188         }
 189     }
 190 
 191     @SuppressWarnings("serial") // Superclass is not serializable across versions
 192     public static class InternalFrameBorder extends AbstractBorder implements UIResource {
 193         private static final int corner = 14;
 194 
 195         public void paintBorder(Component c, Graphics g, int x, int y,
 196                           int w, int h) {
 197 
 198             Color background;
 199             Color highlight;
 200             Color shadow;
 201 
 202             if (c instanceof JInternalFrame && ((JInternalFrame)c).isSelected()) {
 203                 background = MetalLookAndFeel.getPrimaryControlDarkShadow();
 204                 highlight = MetalLookAndFeel.getPrimaryControlShadow();
 205                 shadow = MetalLookAndFeel.getPrimaryControlInfo();
 206             } else {
 207                 background = MetalLookAndFeel.getControlDarkShadow();
 208                 highlight = MetalLookAndFeel.getControlShadow();
 209                 shadow = MetalLookAndFeel.getControlInfo();
 210             }
 211 
 212               g.setColor(background);
 213               // Draw outermost lines
 214               g.drawLine( 1, 0, w-2, 0);
 215               g.drawLine( 0, 1, 0, h-2);
 216               g.drawLine( w-1, 1, w-1, h-2);
 217               g.drawLine( 1, h-1, w-2, h-1);
 218 
 219               // Draw the bulk of the border
 220               for (int i = 1; i < 5; i++) {
 221                   g.drawRect(x+i,y+i,w-(i*2)-1, h-(i*2)-1);
 222               }
 223 
 224               if (c instanceof JInternalFrame &&
 225                                ((JInternalFrame)c).isResizable()) {
 226                   g.setColor(highlight);
 227                   // Draw the Long highlight lines
 228                   g.drawLine( corner+1, 3, w-corner, 3);
 229                   g.drawLine( 3, corner+1, 3, h-corner);
 230                   g.drawLine( w-2, corner+1, w-2, h-corner);
 231                   g.drawLine( corner+1, h-2, w-corner, h-2);
 232 
 233                   g.setColor(shadow);
 234                   // Draw the Long shadow lines
 235                   g.drawLine( corner, 2, w-corner-1, 2);
 236                   g.drawLine( 2, corner, 2, h-corner-1);
 237                   g.drawLine( w-3, corner, w-3, h-corner-1);
 238                   g.drawLine( corner, h-3, w-corner-1, h-3);
 239               }
 240 
 241           }
 242 
 243           public Insets getBorderInsets(Component c, Insets newInsets) {
 244               newInsets.set(5, 5, 5, 5);
 245               return newInsets;
 246           }
 247     }
 248 
 249     /**
 250      * Border for a Frame.
 251      * @since 1.4
 252      */
 253     @SuppressWarnings("serial") // Superclass is not serializable across versions
 254     static class FrameBorder extends AbstractBorder implements UIResource {
 255         private static final int corner = 14;
 256 
 257         public void paintBorder(Component c, Graphics g, int x, int y,
 258             int w, int h) {
 259 
 260             Color background;
 261             Color highlight;
 262             Color shadow;
 263 
 264             Window window = SwingUtilities.getWindowAncestor(c);
 265             if (window != null && window.isActive()) {
 266                 background = MetalLookAndFeel.getPrimaryControlDarkShadow();
 267                 highlight = MetalLookAndFeel.getPrimaryControlShadow();
 268                 shadow = MetalLookAndFeel.getPrimaryControlInfo();
 269             } else {
 270                 background = MetalLookAndFeel.getControlDarkShadow();
 271                 highlight = MetalLookAndFeel.getControlShadow();
 272                 shadow = MetalLookAndFeel.getControlInfo();
 273             }
 274 
 275             g.setColor(background);
 276             // Draw outermost lines
 277             g.drawLine( x+1, y+0, x+w-2, y+0);
 278             g.drawLine( x+0, y+1, x+0, y +h-2);
 279             g.drawLine( x+w-1, y+1, x+w-1, y+h-2);
 280             g.drawLine( x+1, y+h-1, x+w-2, y+h-1);
 281 
 282             // Draw the bulk of the border
 283             for (int i = 1; i < 5; i++) {
 284                 g.drawRect(x+i,y+i,w-(i*2)-1, h-(i*2)-1);
 285             }
 286 
 287             if ((window instanceof Frame) && ((Frame) window).isResizable()) {
 288                 g.setColor(highlight);
 289                 // Draw the Long highlight lines
 290                 g.drawLine( corner+1, 3, w-corner, 3);
 291                 g.drawLine( 3, corner+1, 3, h-corner);
 292                 g.drawLine( w-2, corner+1, w-2, h-corner);
 293                 g.drawLine( corner+1, h-2, w-corner, h-2);
 294 
 295                 g.setColor(shadow);
 296                 // Draw the Long shadow lines
 297                 g.drawLine( corner, 2, w-corner-1, 2);
 298                 g.drawLine( 2, corner, 2, h-corner-1);
 299                 g.drawLine( w-3, corner, w-3, h-corner-1);
 300                 g.drawLine( corner, h-3, w-corner-1, h-3);
 301             }
 302 
 303         }
 304 
 305         public Insets getBorderInsets(Component c, Insets newInsets)
 306         {
 307             newInsets.set(5, 5, 5, 5);
 308             return newInsets;
 309         }
 310     }
 311 
 312     /**
 313      * Border for a Frame.
 314      * @since 1.4
 315      */
 316     @SuppressWarnings("serial") // Superclass is not serializable across versions
 317     static class DialogBorder extends AbstractBorder implements UIResource
 318     {
 319         private static final int corner = 14;
 320 
 321         protected Color getActiveBackground()
 322         {
 323             return MetalLookAndFeel.getPrimaryControlDarkShadow();
 324         }
 325 
 326         protected Color getActiveHighlight()
 327         {
 328             return MetalLookAndFeel.getPrimaryControlShadow();
 329         }
 330 
 331         protected Color getActiveShadow()
 332         {
 333             return MetalLookAndFeel.getPrimaryControlInfo();
 334         }
 335 
 336         protected Color getInactiveBackground()
 337         {
 338             return MetalLookAndFeel.getControlDarkShadow();
 339         }
 340 
 341         protected Color getInactiveHighlight()
 342         {
 343             return MetalLookAndFeel.getControlShadow();
 344         }
 345 
 346         protected Color getInactiveShadow()
 347         {
 348             return MetalLookAndFeel.getControlInfo();
 349         }
 350 
 351         public void paintBorder(Component c, Graphics g, int x, int y, int w, int h)
 352         {
 353             Color background;
 354             Color highlight;
 355             Color shadow;
 356 
 357             Window window = SwingUtilities.getWindowAncestor(c);
 358             if (window != null && window.isActive()) {
 359                 background = getActiveBackground();
 360                 highlight = getActiveHighlight();
 361                 shadow = getActiveShadow();
 362             } else {
 363                 background = getInactiveBackground();
 364                 highlight = getInactiveHighlight();
 365                 shadow = getInactiveShadow();
 366             }
 367 
 368             g.setColor(background);
 369             // Draw outermost lines
 370             g.drawLine( x + 1, y + 0, x + w-2, y + 0);
 371             g.drawLine( x + 0, y + 1, x + 0, y + h - 2);
 372             g.drawLine( x + w - 1, y + 1, x + w - 1, y + h - 2);
 373             g.drawLine( x + 1, y + h - 1, x + w - 2, y + h - 1);
 374 
 375             // Draw the bulk of the border
 376             for (int i = 1; i < 5; i++) {
 377                 g.drawRect(x+i,y+i,w-(i*2)-1, h-(i*2)-1);
 378             }
 379 
 380 
 381             if ((window instanceof Dialog) && ((Dialog) window).isResizable()) {
 382                 g.setColor(highlight);
 383                 // Draw the Long highlight lines
 384                 g.drawLine( corner+1, 3, w-corner, 3);
 385                 g.drawLine( 3, corner+1, 3, h-corner);
 386                 g.drawLine( w-2, corner+1, w-2, h-corner);
 387                 g.drawLine( corner+1, h-2, w-corner, h-2);
 388 
 389                 g.setColor(shadow);
 390                 // Draw the Long shadow lines
 391                 g.drawLine( corner, 2, w-corner-1, 2);
 392                 g.drawLine( 2, corner, 2, h-corner-1);
 393                 g.drawLine( w-3, corner, w-3, h-corner-1);
 394                 g.drawLine( corner, h-3, w-corner-1, h-3);
 395             }
 396 
 397         }
 398 
 399         public Insets getBorderInsets(Component c, Insets newInsets)
 400         {
 401             newInsets.set(5, 5, 5, 5);
 402             return newInsets;
 403         }
 404     }
 405 
 406     /**
 407      * Border for an Error Dialog.
 408      * @since 1.4
 409      */
 410     @SuppressWarnings("serial") // Superclass is not serializable across versions
 411     static class ErrorDialogBorder extends DialogBorder implements UIResource
 412     {
 413         protected Color getActiveBackground() {
 414             return UIManager.getColor("OptionPane.errorDialog.border.background");
 415         }
 416     }
 417 
 418 
 419     /**
 420      * Border for a QuestionDialog.  Also used for a JFileChooser and a
 421      * JColorChooser..
 422      * @since 1.4
 423      */
 424     @SuppressWarnings("serial") // Superclass is not serializable across versions
 425     static class QuestionDialogBorder extends DialogBorder implements UIResource
 426     {
 427         protected Color getActiveBackground() {
 428             return UIManager.getColor("OptionPane.questionDialog.border.background");
 429         }
 430     }
 431 
 432 
 433     /**
 434      * Border for a Warning Dialog.
 435      * @since 1.4
 436      */
 437     @SuppressWarnings("serial") // Superclass is not serializable across versions
 438     static class WarningDialogBorder extends DialogBorder implements UIResource
 439     {
 440         protected Color getActiveBackground() {
 441             return UIManager.getColor("OptionPane.warningDialog.border.background");
 442         }
 443     }
 444 
 445 
 446     /**
 447      * Border for a Palette.
 448      * @since 1.3
 449      */
 450     @SuppressWarnings("serial") // Superclass is not serializable across versions
 451     public static class PaletteBorder extends AbstractBorder implements UIResource {
 452         int titleHeight = 0;
 453 
 454         public void paintBorder( Component c, Graphics g, int x, int y, int w, int h ) {
 455 
 456             g.translate(x,y);
 457             g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
 458             g.drawLine(0, 1, 0, h-2);
 459             g.drawLine(1, h-1, w-2, h-1);
 460             g.drawLine(w-1,  1, w-1, h-2);
 461             g.drawLine( 1, 0, w-2, 0);
 462             g.drawRect(1,1, w-3, h-3);
 463             g.translate(-x,-y);
 464 
 465         }
 466 
 467         public Insets getBorderInsets(Component c, Insets newInsets) {
 468             newInsets.set(1, 1, 1, 1);
 469             return newInsets;
 470         }
 471     }
 472 
 473     @SuppressWarnings("serial") // Superclass is not serializable across versions
 474     public static class OptionDialogBorder extends AbstractBorder implements UIResource {
 475         int titleHeight = 0;
 476 
 477         public void paintBorder( Component c, Graphics g, int x, int y, int w, int h ) {
 478 
 479             g.translate(x,y);
 480 
 481             int messageType = JOptionPane.PLAIN_MESSAGE;
 482             if (c instanceof JInternalFrame) {
 483                 Object obj = ((JInternalFrame) c).getClientProperty(
 484                               "JInternalFrame.messageType");
 485                 if (obj instanceof Integer) {
 486                     messageType = (Integer) obj;
 487                 }
 488             }
 489 
 490             Color borderColor;
 491 
 492             switch (messageType) {
 493             case(JOptionPane.ERROR_MESSAGE):
 494                 borderColor = UIManager.getColor(
 495                     "OptionPane.errorDialog.border.background");
 496                 break;
 497             case(JOptionPane.QUESTION_MESSAGE):
 498                 borderColor = UIManager.getColor(
 499                     "OptionPane.questionDialog.border.background");
 500                 break;
 501             case(JOptionPane.WARNING_MESSAGE):
 502                 borderColor = UIManager.getColor(
 503                     "OptionPane.warningDialog.border.background");
 504                 break;
 505             case(JOptionPane.INFORMATION_MESSAGE):
 506             case(JOptionPane.PLAIN_MESSAGE):
 507             default:
 508                 borderColor = MetalLookAndFeel.getPrimaryControlDarkShadow();
 509                 break;
 510             }
 511 
 512             g.setColor(borderColor);
 513 
 514               // Draw outermost lines
 515               g.drawLine( 1, 0, w-2, 0);
 516               g.drawLine( 0, 1, 0, h-2);
 517               g.drawLine( w-1, 1, w-1, h-2);
 518               g.drawLine( 1, h-1, w-2, h-1);
 519 
 520               // Draw the bulk of the border
 521               for (int i = 1; i < 3; i++) {
 522                   g.drawRect(i, i, w-(i*2)-1, h-(i*2)-1);
 523               }
 524 
 525             g.translate(-x,-y);
 526 
 527         }
 528 
 529         public Insets getBorderInsets(Component c, Insets newInsets) {
 530             newInsets.set(3, 3, 3, 3);
 531             return newInsets;
 532         }
 533     }
 534 
 535     @SuppressWarnings("serial") // Superclass is not serializable across versions
 536     public static class MenuBarBorder extends AbstractBorder implements UIResource {
 537         protected static Insets borderInsets = new Insets( 1, 0, 1, 0 );
 538 
 539         public void paintBorder( Component c, Graphics g, int x, int y, int w, int h ) {
 540             g.translate( x, y );
 541 
 542             if (MetalLookAndFeel.usingOcean()) {
 543                 // Only paint a border if we're not next to a horizontal
 544                 // toolbar
 545                 if ((c instanceof JMenuBar) && !MetalToolBarUI.doesMenuBarBorderToolBar((JMenuBar)c)) {
 546                     g.setColor(MetalLookAndFeel.getControl());
 547                     g.drawLine(0, h - 2, w, h - 2);
 548                     g.setColor(UIManager.getColor("MenuBar.borderColor"));
 549                     g.drawLine(0, h - 1, w, h - 1);
 550                 }
 551             }
 552             else {
 553                 g.setColor( MetalLookAndFeel.getControlShadow() );
 554                 g.drawLine( 0, h-1, w, h-1 );
 555             }
 556 
 557             g.translate( -x, -y );
 558 
 559         }
 560 
 561         public Insets getBorderInsets(Component c, Insets newInsets) {
 562             if (MetalLookAndFeel.usingOcean()) {
 563                 newInsets.set(0, 0, 2, 0);
 564             }
 565             else {
 566                 newInsets.set(1, 0, 1, 0);
 567             }
 568             return newInsets;
 569         }
 570     }
 571 
 572     @SuppressWarnings("serial") // Superclass is not serializable across versions
 573     public static class MenuItemBorder extends AbstractBorder implements UIResource {
 574         protected static Insets borderInsets = new Insets( 2, 2, 2, 2 );
 575 
 576         public void paintBorder( Component c, Graphics g, int x, int y, int w, int h ) {
 577             if (!(c instanceof JMenuItem)) {
 578                 return;
 579             }
 580             JMenuItem b = (JMenuItem) c;
 581             ButtonModel model = b.getModel();
 582 
 583             g.translate( x, y );
 584 
 585             if ( c.getParent() instanceof JMenuBar ) {
 586                 if ( model.isArmed() || model.isSelected() ) {
 587                     g.setColor( MetalLookAndFeel.getControlDarkShadow() );
 588                     g.drawLine( 0, 0, w - 2, 0 );
 589                     g.drawLine( 0, 0, 0, h - 1 );
 590                     g.drawLine( w - 2, 2, w - 2, h - 1 );
 591 
 592                     g.setColor( MetalLookAndFeel.getPrimaryControlHighlight() );
 593                     g.drawLine( w - 1, 1, w - 1, h - 1 );
 594 
 595                     g.setColor( MetalLookAndFeel.getMenuBackground() );
 596                     g.drawLine( w - 1, 0, w - 1, 0 );
 597                 }
 598             } else {
 599                 if (  model.isArmed() || ( c instanceof JMenu && model.isSelected() ) ) {
 600                     g.setColor( MetalLookAndFeel.getPrimaryControlDarkShadow() );
 601                     g.drawLine( 0, 0, w - 1, 0 );
 602 
 603                     g.setColor( MetalLookAndFeel.getPrimaryControlHighlight() );
 604                     g.drawLine( 0, h - 1, w - 1, h - 1 );
 605                 } else {
 606                     g.setColor( MetalLookAndFeel.getPrimaryControlHighlight() );
 607                     g.drawLine( 0, 0, 0, h - 1 );
 608                 }
 609             }
 610 
 611             g.translate( -x, -y );
 612         }
 613 
 614         public Insets getBorderInsets(Component c, Insets newInsets) {
 615             newInsets.set(2, 2, 2, 2);
 616             return newInsets;
 617         }
 618     }
 619 
 620     @SuppressWarnings("serial") // Superclass is not serializable across versions
 621     public static class PopupMenuBorder extends AbstractBorder implements UIResource {
 622         protected static Insets borderInsets = new Insets( 3, 1, 2, 1 );
 623 
 624         public void paintBorder( Component c, Graphics g, int x, int y, int w, int h ) {
 625             g.translate( x, y );
 626 
 627             g.setColor( MetalLookAndFeel.getPrimaryControlDarkShadow() );
 628             g.drawRect( 0, 0, w - 1, h - 1 );
 629 
 630             g.setColor( MetalLookAndFeel.getPrimaryControlHighlight() );
 631             g.drawLine( 1, 1, w - 2, 1 );
 632             g.drawLine( 1, 2, 1, 2 );
 633             g.drawLine( 1, h - 2, 1, h - 2 );
 634 
 635             g.translate( -x, -y );
 636 
 637         }
 638 
 639         public Insets getBorderInsets(Component c, Insets newInsets) {
 640             newInsets.set(3, 1, 2, 1);
 641             return newInsets;
 642         }
 643     }
 644 
 645     @SuppressWarnings("serial") // Superclass is not serializable across versions
 646     public static class RolloverButtonBorder extends ButtonBorder {
 647 
 648         public void paintBorder( Component c, Graphics g, int x, int y, int w, int h ) {
 649             AbstractButton b = (AbstractButton) c;
 650             ButtonModel model = b.getModel();
 651 
 652             if ( model.isRollover() && !( model.isPressed() && !model.isArmed() ) ) {
 653                 super.paintBorder( c, g, x, y, w, h );
 654             }
 655         }
 656 
 657     }
 658 
 659     /**
 660      * A border which is like a Margin border but it will only honor the margin
 661      * if the margin has been explicitly set by the developer.
 662      *
 663      * Note: This is identical to the package private class
 664      * BasicBorders.RolloverMarginBorder and should probably be consolidated.
 665      */
 666     @SuppressWarnings("serial") // Superclass is not serializable across versions
 667     static class RolloverMarginBorder extends EmptyBorder {
 668 
 669         public RolloverMarginBorder() {
 670             super(3,3,3,3); // hardcoded margin for JLF requirements.
 671         }
 672 
 673         public Insets getBorderInsets(Component c, Insets insets) {
 674             Insets margin = null;
 675 
 676             if (c instanceof AbstractButton) {
 677                 margin = ((AbstractButton)c).getMargin();
 678             }
 679             if (margin == null || margin instanceof UIResource) {
 680                 // default margin so replace
 681                 insets.left = left;
 682                 insets.top = top;
 683                 insets.right = right;
 684                 insets.bottom = bottom;
 685             } else {
 686                 // Margin which has been explicitly set by the user.
 687                 insets.left = margin.left;
 688                 insets.top = margin.top;
 689                 insets.right = margin.right;
 690                 insets.bottom = margin.bottom;
 691             }
 692             return insets;
 693         }
 694     }
 695 
 696     @SuppressWarnings("serial") // Superclass is not serializable across versions
 697     public static class ToolBarBorder extends AbstractBorder implements UIResource, SwingConstants
 698     {
 699         protected MetalBumps bumps = new MetalBumps( 10, 10,
 700                                       MetalLookAndFeel.getControlHighlight(),
 701                                       MetalLookAndFeel.getControlDarkShadow(),
 702                                      UIManager.getColor("ToolBar.background"));
 703 
 704         public void paintBorder( Component c, Graphics g, int x, int y, int w, int h )
 705         {
 706             if (!(c instanceof JToolBar)) {
 707                 return;
 708             }
 709             g.translate( x, y );
 710 
 711             if ( ((JToolBar) c).isFloatable() )
 712             {
 713                 if ( ((JToolBar) c).getOrientation() == HORIZONTAL )
 714                 {
 715                     int shift = MetalLookAndFeel.usingOcean() ? -1 : 0;
 716                     bumps.setBumpArea( 10, h - 4 );
 717                     if( MetalUtils.isLeftToRight(c) ) {
 718                         bumps.paintIcon( c, g, 2, 2 + shift );
 719                     } else {
 720                         bumps.paintIcon( c, g, w-12,
 721                                          2 + shift );
 722                     }
 723                 }
 724                 else // vertical
 725                 {
 726                     bumps.setBumpArea( w - 4, 10 );
 727                     bumps.paintIcon( c, g, 2, 2 );
 728                 }
 729 
 730             }
 731 
 732             if (((JToolBar) c).getOrientation() == HORIZONTAL &&
 733                                MetalLookAndFeel.usingOcean()) {
 734                 g.setColor(MetalLookAndFeel.getControl());
 735                 g.drawLine(0, h - 2, w, h - 2);
 736                 g.setColor(UIManager.getColor("ToolBar.borderColor"));
 737                 g.drawLine(0, h - 1, w, h - 1);
 738             }
 739 
 740             g.translate( -x, -y );
 741         }
 742 
 743         public Insets getBorderInsets(Component c, Insets newInsets) {
 744             if (MetalLookAndFeel.usingOcean()) {
 745                 newInsets.set(1, 2, 3, 2);
 746             }
 747             else {
 748                 newInsets.top = newInsets.left = newInsets.bottom = newInsets.right = 2;
 749             }
 750 
 751             if (!(c instanceof JToolBar)) {
 752                 return newInsets;
 753             }
 754             if ( ((JToolBar) c).isFloatable() ) {
 755                 if ( ((JToolBar) c).getOrientation() == HORIZONTAL ) {
 756                     if (c.getComponentOrientation().isLeftToRight()) {
 757                         newInsets.left = 16;
 758                     } else {
 759                         newInsets.right = 16;
 760                     }
 761                 } else {// vertical
 762                     newInsets.top = 16;
 763                 }
 764             }
 765 
 766             Insets margin = ((JToolBar) c).getMargin();
 767 
 768             if ( margin != null ) {
 769                 newInsets.left   += margin.left;
 770                 newInsets.top    += margin.top;
 771                 newInsets.right  += margin.right;
 772                 newInsets.bottom += margin.bottom;
 773             }
 774 
 775             return newInsets;
 776         }
 777     }
 778 
 779     private static Border buttonBorder;
 780 
 781     /**
 782      * Returns a border instance for a JButton
 783      * @since 1.3
 784      */
 785     public static Border getButtonBorder() {
 786         if (buttonBorder == null) {
 787             buttonBorder = new BorderUIResource.CompoundBorderUIResource(
 788                                                    new MetalBorders.ButtonBorder(),
 789                                                    new BasicBorders.MarginBorder());
 790         }
 791         return buttonBorder;
 792     }
 793 
 794     private static Border textBorder;
 795 
 796     /**
 797      * Returns a border instance for a text component
 798      * @since 1.3
 799      */
 800     public static Border getTextBorder() {
 801         if (textBorder == null) {
 802             textBorder = new BorderUIResource.CompoundBorderUIResource(
 803                                                    new MetalBorders.Flush3DBorder(),
 804                                                    new BasicBorders.MarginBorder());
 805         }
 806         return textBorder;
 807     }
 808 
 809     private static Border textFieldBorder;
 810 
 811     /**
 812      * Returns a border instance for a JTextField
 813      * @since 1.3
 814      */
 815     public static Border getTextFieldBorder() {
 816         if (textFieldBorder == null) {
 817             textFieldBorder = new BorderUIResource.CompoundBorderUIResource(
 818                                                    new MetalBorders.TextFieldBorder(),
 819                                                    new BasicBorders.MarginBorder());
 820         }
 821         return textFieldBorder;
 822     }
 823 
 824     @SuppressWarnings("serial") // Superclass is not serializable across versions
 825     public static class TextFieldBorder extends Flush3DBorder {
 826 
 827         public void paintBorder(Component c, Graphics g, int x, int y,
 828                                 int w, int h) {
 829 
 830           if (!(c instanceof JTextComponent)) {
 831                 // special case for non-text components (bug ID 4144840)
 832                 if (c.isEnabled()) {
 833                     MetalUtils.drawFlush3DBorder(g, x, y, w, h);
 834                 } else {
 835                     MetalUtils.drawDisabledBorder(g, x, y, w, h);
 836                 }
 837                 return;
 838             }
 839 
 840             if (c.isEnabled() && ((JTextComponent)c).isEditable()) {
 841                 MetalUtils.drawFlush3DBorder(g, x, y, w, h);
 842             } else {
 843                 MetalUtils.drawDisabledBorder(g, x, y, w, h);
 844             }
 845 
 846         }
 847     }
 848 
 849     @SuppressWarnings("serial") // Superclass is not serializable across versions
 850     public static class ScrollPaneBorder extends AbstractBorder implements UIResource {
 851         public void paintBorder(Component c, Graphics g, int x, int y,
 852                           int w, int h) {
 853 
 854             if (!(c instanceof JScrollPane)) {
 855                 return;
 856             }
 857             JScrollPane scroll = (JScrollPane)c;
 858             JComponent colHeader = scroll.getColumnHeader();
 859             int colHeaderHeight = 0;
 860             if (colHeader != null)
 861                colHeaderHeight = colHeader.getHeight();
 862 
 863             JComponent rowHeader = scroll.getRowHeader();
 864             int rowHeaderWidth = 0;
 865             if (rowHeader != null)
 866                rowHeaderWidth = rowHeader.getWidth();
 867 
 868 
 869             g.translate( x, y);
 870 
 871             g.setColor( MetalLookAndFeel.getControlDarkShadow() );
 872             g.drawRect( 0, 0, w-2, h-2 );
 873             g.setColor( MetalLookAndFeel.getControlHighlight() );
 874 
 875             g.drawLine( w-1, 1, w-1, h-1);
 876             g.drawLine( 1, h-1, w-1, h-1);
 877 
 878             g.setColor( MetalLookAndFeel.getControl() );
 879             g.drawLine( w-2, 2+colHeaderHeight, w-2, 2+colHeaderHeight );
 880             g.drawLine( 1+rowHeaderWidth, h-2, 1+rowHeaderWidth, h-2 );
 881 
 882             g.translate( -x, -y);
 883 
 884         }
 885 
 886         public Insets getBorderInsets(Component c, Insets insets) {
 887             insets.set(1, 1, 2, 2);
 888             return insets;
 889         }
 890     }
 891 
 892     private static Border toggleButtonBorder;
 893 
 894     /**
 895      * Returns a border instance for a JToggleButton
 896      * @since 1.3
 897      */
 898     public static Border getToggleButtonBorder() {
 899         if (toggleButtonBorder == null) {
 900             toggleButtonBorder = new BorderUIResource.CompoundBorderUIResource(
 901                                                    new MetalBorders.ToggleButtonBorder(),
 902                                                    new BasicBorders.MarginBorder());
 903         }
 904         return toggleButtonBorder;
 905     }
 906 
 907     /**
 908      * @since 1.3
 909      */
 910     @SuppressWarnings("serial") // Superclass is not serializable across versions
 911     public static class ToggleButtonBorder extends ButtonBorder {
 912         public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
 913             AbstractButton button = (AbstractButton)c;
 914             ButtonModel model = button.getModel();
 915             if (MetalLookAndFeel.usingOcean()) {
 916                 if(model.isArmed() || !button.isEnabled()) {
 917                     super.paintBorder(c, g, x, y, w, h);
 918                 }
 919                 else {
 920                  g.setColor(MetalLookAndFeel.getControlDarkShadow());
 921                  g.drawRect(0, 0, w - 1, h - 1);
 922             }
 923             return;
 924         }
 925             if (! c.isEnabled() ) {
 926                 MetalUtils.drawDisabledBorder( g, x, y, w-1, h-1 );
 927             } else {
 928                 if ( model.isPressed() && model.isArmed() ) {
 929                    MetalUtils.drawPressed3DBorder( g, x, y, w, h );
 930                 } else if ( model.isSelected() ) {
 931                     MetalUtils.drawDark3DBorder( g, x, y, w, h );
 932                 } else {
 933                     MetalUtils.drawFlush3DBorder( g, x, y, w, h );
 934                 }
 935             }
 936         }
 937     }
 938 
 939     /**
 940      * Border for a Table Header
 941      * @since 1.3
 942      */
 943     @SuppressWarnings("serial") // Superclass is not serializable across versions
 944     public static class TableHeaderBorder extends javax.swing.border.AbstractBorder {
 945         protected Insets editorBorderInsets = new Insets( 2, 2, 2, 0 );
 946 
 947         public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
 948             g.translate( x, y );
 949 
 950             g.setColor( MetalLookAndFeel.getControlDarkShadow() );
 951             g.drawLine( w-1, 0, w-1, h-1 );
 952             g.drawLine( 1, h-1, w-1, h-1 );
 953             g.setColor( MetalLookAndFeel.getControlHighlight() );
 954             g.drawLine( 0, 0, w-2, 0 );
 955             g.drawLine( 0, 0, 0, h-2 );
 956 
 957             g.translate( -x, -y );
 958         }
 959 
 960         public Insets getBorderInsets(Component c, Insets insets) {
 961             insets.set(2, 2, 2, 0);
 962             return insets;
 963         }
 964     }
 965 
 966     /**
 967      * Returns a border instance for a Desktop Icon
 968      * @since 1.3
 969      */
 970     public static Border getDesktopIconBorder() {
 971         return new BorderUIResource.CompoundBorderUIResource(
 972                                           new LineBorder(MetalLookAndFeel.getControlDarkShadow(), 1),
 973                                           new MatteBorder (2,2,1,2, MetalLookAndFeel.getControl()));
 974     }
 975 
 976     static Border getToolBarRolloverBorder() {
 977         if (MetalLookAndFeel.usingOcean()) {
 978             return new CompoundBorder(
 979                 new MetalBorders.ButtonBorder(),
 980                 new MetalBorders.RolloverMarginBorder());
 981         }
 982         return new CompoundBorder(new MetalBorders.RolloverButtonBorder(),
 983                                   new MetalBorders.RolloverMarginBorder());
 984     }
 985 
 986     static Border getToolBarNonrolloverBorder() {
 987         if (MetalLookAndFeel.usingOcean()) {
 988             new CompoundBorder(
 989                 new MetalBorders.ButtonBorder(),
 990                 new MetalBorders.RolloverMarginBorder());
 991         }
 992         return new CompoundBorder(new MetalBorders.ButtonBorder(),
 993                                   new MetalBorders.RolloverMarginBorder());
 994     }
 995 }