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         protected MetalBumps bumps = new MetalBumps( 10, 10,
 743                                       MetalLookAndFeel.getControlHighlight(),
 744                                       MetalLookAndFeel.getControlDarkShadow(),
 745                                      UIManager.getColor("ToolBar.background"));
 746 
 747         public void paintBorder( Component c, Graphics g, int x, int y, int w, int h )
 748         {
 749             if (!(c instanceof JToolBar)) {
 750                 return;
 751             }
 752             g.translate( x, y );
 753 
 754             if ( ((JToolBar) c).isFloatable() )
 755             {
 756                 if ( ((JToolBar) c).getOrientation() == HORIZONTAL )
 757                 {
 758                     int shift = MetalLookAndFeel.usingOcean() ? -1 : 0;
 759                     bumps.setBumpArea( 10, h - 4 );
 760                     if( MetalUtils.isLeftToRight(c) ) {
 761                         bumps.paintIcon( c, g, 2, 2 + shift );
 762                     } else {
 763                         bumps.paintIcon( c, g, w-12,
 764                                          2 + shift );
 765                     }
 766                 }
 767                 else // vertical
 768                 {
 769                     bumps.setBumpArea( w - 4, 10 );
 770                     bumps.paintIcon( c, g, 2, 2 );
 771                 }
 772 
 773             }
 774 
 775             if (((JToolBar) c).getOrientation() == HORIZONTAL &&
 776                                MetalLookAndFeel.usingOcean()) {
 777                 g.setColor(MetalLookAndFeel.getControl());
 778                 g.drawLine(0, h - 2, w, h - 2);
 779                 g.setColor(UIManager.getColor("ToolBar.borderColor"));
 780                 g.drawLine(0, h - 1, w, h - 1);
 781             }
 782 
 783             g.translate( -x, -y );
 784         }
 785 
 786         public Insets getBorderInsets(Component c, Insets newInsets) {
 787             if (MetalLookAndFeel.usingOcean()) {
 788                 newInsets.set(1, 2, 3, 2);
 789             }
 790             else {
 791                 newInsets.top = newInsets.left = newInsets.bottom = newInsets.right = 2;
 792             }
 793 
 794             if (!(c instanceof JToolBar)) {
 795                 return newInsets;
 796             }
 797             if ( ((JToolBar) c).isFloatable() ) {
 798                 if ( ((JToolBar) c).getOrientation() == HORIZONTAL ) {
 799                     if (c.getComponentOrientation().isLeftToRight()) {
 800                         newInsets.left = 16;
 801                     } else {
 802                         newInsets.right = 16;
 803                     }
 804                 } else {// vertical
 805                     newInsets.top = 16;
 806                 }
 807             }
 808 
 809             Insets margin = ((JToolBar) c).getMargin();
 810 
 811             if ( margin != null ) {
 812                 newInsets.left   += margin.left;
 813                 newInsets.top    += margin.top;
 814                 newInsets.right  += margin.right;
 815                 newInsets.bottom += margin.bottom;
 816             }
 817 
 818             return newInsets;
 819         }
 820     }
 821 
 822     private static Border buttonBorder;
 823 
 824     /**
 825      * Returns a border instance for a {@code JButton}.
 826      *
 827      * @return a border instance for a {@code JButton}
 828      * @since 1.3
 829      */
 830     public static Border getButtonBorder() {
 831         if (buttonBorder == null) {
 832             buttonBorder = new BorderUIResource.CompoundBorderUIResource(
 833                                                    new MetalBorders.ButtonBorder(),
 834                                                    new BasicBorders.MarginBorder());
 835         }
 836         return buttonBorder;
 837     }
 838 
 839     private static Border textBorder;
 840 
 841     /**
 842      * Returns a border instance for a text component.
 843      *
 844      * @return a border instance for a text component
 845      * @since 1.3
 846      */
 847     public static Border getTextBorder() {
 848         if (textBorder == null) {
 849             textBorder = new BorderUIResource.CompoundBorderUIResource(
 850                                                    new MetalBorders.Flush3DBorder(),
 851                                                    new BasicBorders.MarginBorder());
 852         }
 853         return textBorder;
 854     }
 855 
 856     private static Border textFieldBorder;
 857 
 858     /**
 859      * Returns a border instance for a {@code JTextField}.
 860      *
 861      * @return a border instance for a {@code JTextField}
 862      * @since 1.3
 863      */
 864     public static Border getTextFieldBorder() {
 865         if (textFieldBorder == null) {
 866             textFieldBorder = new BorderUIResource.CompoundBorderUIResource(
 867                                                    new MetalBorders.TextFieldBorder(),
 868                                                    new BasicBorders.MarginBorder());
 869         }
 870         return textFieldBorder;
 871     }
 872 
 873     /**
 874      * The class represents the border of a {@code JTestField}.
 875      */
 876     @SuppressWarnings("serial") // Superclass is not serializable across versions
 877     public static class TextFieldBorder extends Flush3DBorder {
 878 
 879         public void paintBorder(Component c, Graphics g, int x, int y,
 880                                 int w, int h) {
 881 
 882           if (!(c instanceof JTextComponent)) {
 883                 // special case for non-text components (bug ID 4144840)
 884                 if (c.isEnabled()) {
 885                     MetalUtils.drawFlush3DBorder(g, x, y, w, h);
 886                 } else {
 887                     MetalUtils.drawDisabledBorder(g, x, y, w, h);
 888                 }
 889                 return;
 890             }
 891 
 892             if (c.isEnabled() && ((JTextComponent)c).isEditable()) {
 893                 MetalUtils.drawFlush3DBorder(g, x, y, w, h);
 894             } else {
 895                 MetalUtils.drawDisabledBorder(g, x, y, w, h);
 896             }
 897 
 898         }
 899     }
 900 
 901     /**
 902      * The class represents the border of a {@code JScrollPane}.
 903      */
 904     @SuppressWarnings("serial") // Superclass is not serializable across versions
 905     public static class ScrollPaneBorder extends AbstractBorder implements UIResource {
 906         public void paintBorder(Component c, Graphics g, int x, int y,
 907                           int w, int h) {
 908 
 909             if (!(c instanceof JScrollPane)) {
 910                 return;
 911             }
 912             JScrollPane scroll = (JScrollPane)c;
 913             JComponent colHeader = scroll.getColumnHeader();
 914             int colHeaderHeight = 0;
 915             if (colHeader != null)
 916                colHeaderHeight = colHeader.getHeight();
 917 
 918             JComponent rowHeader = scroll.getRowHeader();
 919             int rowHeaderWidth = 0;
 920             if (rowHeader != null)
 921                rowHeaderWidth = rowHeader.getWidth();
 922 
 923 
 924             g.translate( x, y);
 925 
 926             g.setColor( MetalLookAndFeel.getControlDarkShadow() );
 927             g.drawRect( 0, 0, w-2, h-2 );
 928             g.setColor( MetalLookAndFeel.getControlHighlight() );
 929 
 930             g.drawLine( w-1, 1, w-1, h-1);
 931             g.drawLine( 1, h-1, w-1, h-1);
 932 
 933             g.setColor( MetalLookAndFeel.getControl() );
 934             g.drawLine( w-2, 2+colHeaderHeight, w-2, 2+colHeaderHeight );
 935             g.drawLine( 1+rowHeaderWidth, h-2, 1+rowHeaderWidth, h-2 );
 936 
 937             g.translate( -x, -y);
 938 
 939         }
 940 
 941         public Insets getBorderInsets(Component c, Insets insets) {
 942             insets.set(1, 1, 2, 2);
 943             return insets;
 944         }
 945     }
 946 
 947     private static Border toggleButtonBorder;
 948 
 949     /**
 950      * Returns a border instance for a {@code JToggleButton}.
 951      *
 952      * @return a border instance for a {@code JToggleButton}
 953      * @since 1.3
 954      */
 955     public static Border getToggleButtonBorder() {
 956         if (toggleButtonBorder == null) {
 957             toggleButtonBorder = new BorderUIResource.CompoundBorderUIResource(
 958                                                    new MetalBorders.ToggleButtonBorder(),
 959                                                    new BasicBorders.MarginBorder());
 960         }
 961         return toggleButtonBorder;
 962     }
 963 
 964     /**
 965      * @since 1.3
 966      */
 967     @SuppressWarnings("serial") // Superclass is not serializable across versions
 968     public static class ToggleButtonBorder extends ButtonBorder {
 969         public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
 970             AbstractButton button = (AbstractButton)c;
 971             ButtonModel model = button.getModel();
 972             if (MetalLookAndFeel.usingOcean()) {
 973                 if(model.isArmed() || !button.isEnabled()) {
 974                     super.paintBorder(c, g, x, y, w, h);
 975                 }
 976                 else {
 977                  g.setColor(MetalLookAndFeel.getControlDarkShadow());
 978                  g.drawRect(0, 0, w - 1, h - 1);
 979             }
 980             return;
 981         }
 982             if (! c.isEnabled() ) {
 983                 MetalUtils.drawDisabledBorder( g, x, y, w-1, h-1 );
 984             } else {
 985                 if ( model.isPressed() && model.isArmed() ) {
 986                    MetalUtils.drawPressed3DBorder( g, x, y, w, h );
 987                 } else if ( model.isSelected() ) {
 988                     MetalUtils.drawDark3DBorder( g, x, y, w, h );
 989                 } else {
 990                     MetalUtils.drawFlush3DBorder( g, x, y, w, h );
 991                 }
 992             }
 993         }
 994     }
 995 
 996     /**
 997      * Border for a Table Header
 998      * @since 1.3
 999      */
1000     @SuppressWarnings("serial") // Superclass is not serializable across versions
1001     public static class TableHeaderBorder extends javax.swing.border.AbstractBorder {
1002 
1003         /**
1004          * The border insets.
1005          */
1006         protected Insets editorBorderInsets = new Insets( 2, 2, 2, 0 );
1007 
1008         public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
1009             g.translate( x, y );
1010 
1011             g.setColor( MetalLookAndFeel.getControlDarkShadow() );
1012             g.drawLine( w-1, 0, w-1, h-1 );
1013             g.drawLine( 1, h-1, w-1, h-1 );
1014             g.setColor( MetalLookAndFeel.getControlHighlight() );
1015             g.drawLine( 0, 0, w-2, 0 );
1016             g.drawLine( 0, 0, 0, h-2 );
1017 
1018             g.translate( -x, -y );
1019         }
1020 
1021         public Insets getBorderInsets(Component c, Insets insets) {
1022             insets.set(2, 2, 2, 0);
1023             return insets;
1024         }
1025     }
1026 
1027     /**
1028      * Returns a border instance for a Desktop Icon.
1029      *
1030      * @return a border instance for a Desktop Icon
1031      * @since 1.3
1032      */
1033     public static Border getDesktopIconBorder() {
1034         return new BorderUIResource.CompoundBorderUIResource(
1035                                           new LineBorder(MetalLookAndFeel.getControlDarkShadow(), 1),
1036                                           new MatteBorder (2,2,1,2, MetalLookAndFeel.getControl()));
1037     }
1038 
1039     static Border getToolBarRolloverBorder() {
1040         if (MetalLookAndFeel.usingOcean()) {
1041             return new CompoundBorder(
1042                 new MetalBorders.ButtonBorder(),
1043                 new MetalBorders.RolloverMarginBorder());
1044         }
1045         return new CompoundBorder(new MetalBorders.RolloverButtonBorder(),
1046                                   new MetalBorders.RolloverMarginBorder());
1047     }
1048 
1049     static Border getToolBarNonrolloverBorder() {
1050         if (MetalLookAndFeel.usingOcean()) {
1051             new CompoundBorder(
1052                 new MetalBorders.ButtonBorder(),
1053                 new MetalBorders.RolloverMarginBorder());
1054         }
1055         return new CompoundBorder(new MetalBorders.ButtonBorder(),
1056                                   new MetalBorders.RolloverMarginBorder());
1057     }
1058 }