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