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