1 /*
   2  * Copyright (c) 1998, 2013, 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 com.sun.java.swing.plaf.windows;
  27 
  28 import javax.swing.*;
  29 import javax.swing.plaf.ButtonUI;
  30 import javax.swing.plaf.UIResource;
  31 
  32 import java.awt.*;
  33 import java.io.Serializable;
  34 
  35 import static com.sun.java.swing.plaf.windows.TMSchema.*;
  36 import static com.sun.java.swing.plaf.windows.XPStyle.Skin;
  37 
  38 import sun.swing.MenuItemCheckIconFactory;
  39 
  40 /**
  41  * Factory object that can vend Icons appropriate for the Windows L & F.
  42  * <p>
  43  * <strong>Warning:</strong>
  44  * Serialized objects of this class will not be compatible with
  45  * future Swing releases.  The current serialization support is appropriate
  46  * for short term storage or RMI between applications running the same
  47  * version of Swing.  A future release of Swing will provide support for
  48  * long term persistence.
  49  *
  50  * @author David Kloba
  51  * @author Georges Saab
  52  * @author Rich Schiavi
  53  */
  54 public class WindowsIconFactory implements Serializable
  55 {
  56     private static Icon frame_closeIcon;
  57     private static Icon frame_iconifyIcon;
  58     private static Icon frame_maxIcon;
  59     private static Icon frame_minIcon;
  60     private static Icon frame_resizeIcon;
  61     private static Icon checkBoxIcon;
  62     private static Icon radioButtonIcon;
  63     private static Icon checkBoxMenuItemIcon;
  64     private static Icon radioButtonMenuItemIcon;
  65     private static Icon menuItemCheckIcon;
  66     private static Icon menuItemArrowIcon;
  67     private static Icon menuArrowIcon;
  68     private static VistaMenuItemCheckIconFactory menuItemCheckIconFactory;
  69 
  70     public static Icon getMenuItemCheckIcon() {
  71         if (menuItemCheckIcon == null) {
  72             menuItemCheckIcon = new MenuItemCheckIcon();
  73         }
  74         return menuItemCheckIcon;
  75     }
  76 
  77     public static Icon getMenuItemArrowIcon() {
  78         if (menuItemArrowIcon == null) {
  79             menuItemArrowIcon = new MenuItemArrowIcon();
  80         }
  81         return menuItemArrowIcon;
  82     }
  83 
  84     public static Icon getMenuArrowIcon() {
  85         if (menuArrowIcon == null) {
  86             menuArrowIcon = new MenuArrowIcon();
  87         }
  88         return menuArrowIcon;
  89     }
  90 
  91     public static Icon getCheckBoxIcon() {
  92         if (checkBoxIcon == null) {
  93             checkBoxIcon = new CheckBoxIcon();
  94         }
  95         return checkBoxIcon;
  96     }
  97 
  98     public static Icon getRadioButtonIcon() {
  99         if (radioButtonIcon == null) {
 100             radioButtonIcon = new RadioButtonIcon();
 101         }
 102         return radioButtonIcon;
 103     }
 104 
 105     public static Icon getCheckBoxMenuItemIcon() {
 106         if (checkBoxMenuItemIcon == null) {
 107             checkBoxMenuItemIcon = new CheckBoxMenuItemIcon();
 108         }
 109         return checkBoxMenuItemIcon;
 110     }
 111 
 112     public static Icon getRadioButtonMenuItemIcon() {
 113         if (radioButtonMenuItemIcon == null) {
 114             radioButtonMenuItemIcon = new RadioButtonMenuItemIcon();
 115         }
 116         return radioButtonMenuItemIcon;
 117     }
 118 
 119     static
 120     synchronized VistaMenuItemCheckIconFactory getMenuItemCheckIconFactory() {
 121         if (menuItemCheckIconFactory == null) {
 122             menuItemCheckIconFactory =
 123                 new VistaMenuItemCheckIconFactory();
 124         }
 125         return menuItemCheckIconFactory;
 126     }
 127 
 128     public static Icon createFrameCloseIcon() {
 129         if (frame_closeIcon == null) {
 130             frame_closeIcon = new FrameButtonIcon(Part.WP_CLOSEBUTTON);
 131         }
 132         return frame_closeIcon;
 133     }
 134 
 135     public static Icon createFrameIconifyIcon() {
 136         if (frame_iconifyIcon == null) {
 137             frame_iconifyIcon = new FrameButtonIcon(Part.WP_MINBUTTON);
 138         }
 139         return frame_iconifyIcon;
 140     }
 141 
 142     public static Icon createFrameMaximizeIcon() {
 143         if (frame_maxIcon == null) {
 144             frame_maxIcon = new FrameButtonIcon(Part.WP_MAXBUTTON);
 145         }
 146         return frame_maxIcon;
 147     }
 148 
 149     public static Icon createFrameMinimizeIcon() {
 150         if (frame_minIcon == null) {
 151             frame_minIcon = new FrameButtonIcon(Part.WP_RESTOREBUTTON);
 152         }
 153         return frame_minIcon;
 154     }
 155 
 156     public static Icon createFrameResizeIcon() {
 157         if(frame_resizeIcon == null)
 158             frame_resizeIcon = new ResizeIcon();
 159         return frame_resizeIcon;
 160     }
 161 
 162 
 163     private static class FrameButtonIcon implements Icon, Serializable {
 164         private Part part;
 165 
 166         private FrameButtonIcon(Part part) {
 167             this.part = part;
 168         }
 169 
 170         public void paintIcon(Component c, Graphics g, int x0, int y0) {
 171             int width = getIconWidth();
 172             int height = getIconHeight();
 173 
 174             XPStyle xp = XPStyle.getXP();
 175             if (xp != null) {
 176                 Skin skin = xp.getSkin(c, part);
 177                 AbstractButton b = (AbstractButton)c;
 178                 ButtonModel model = b.getModel();
 179 
 180                 // Find out if frame is inactive
 181                 JInternalFrame jif = (JInternalFrame)SwingUtilities.
 182                                         getAncestorOfClass(JInternalFrame.class, b);
 183                 boolean jifSelected = (jif != null && jif.isSelected());
 184 
 185                 State state;
 186                 if (jifSelected) {
 187                     if (!model.isEnabled()) {
 188                         state = State.DISABLED;
 189                     } else if (model.isArmed() && model.isPressed()) {
 190                         state = State.PUSHED;
 191                     } else if (model.isRollover()) {
 192                         state = State.HOT;
 193                     } else {
 194                         state = State.NORMAL;
 195                     }
 196                 } else {
 197                     if (!model.isEnabled()) {
 198                         state = State.INACTIVEDISABLED;
 199                     } else if (model.isArmed() && model.isPressed()) {
 200                         state = State.INACTIVEPUSHED;
 201                     } else if (model.isRollover()) {
 202                         state = State.INACTIVEHOT;
 203                     } else {
 204                         state = State.INACTIVENORMAL;
 205                     }
 206                 }
 207                 skin.paintSkin(g, 0, 0, width, height, state);
 208             } else {
 209                 g.setColor(Color.black);
 210                 int x = width / 12 + 2;
 211                 int y = height / 5;
 212                 int h = height - y * 2 - 1;
 213                 int w = width * 3/4 -3;
 214                 int thickness2 = Math.max(height / 8, 2);
 215                 int thickness  = Math.max(width / 15, 1);
 216                 if (part == Part.WP_CLOSEBUTTON) {
 217                     int lineWidth;
 218                     if      (width > 47) lineWidth = 6;
 219                     else if (width > 37) lineWidth = 5;
 220                     else if (width > 26) lineWidth = 4;
 221                     else if (width > 16) lineWidth = 3;
 222                     else if (width > 12) lineWidth = 2;
 223                     else                 lineWidth = 1;
 224                     y = height / 12 + 2;
 225                     if (lineWidth == 1) {
 226                         if (w % 2 == 1) { x++; w++; }
 227                         g.drawLine(x,     y, x+w-2, y+w-2);
 228                         g.drawLine(x+w-2, y, x,     y+w-2);
 229                     } else if (lineWidth == 2) {
 230                         if (w > 6) { x++; w--; }
 231                         g.drawLine(x,     y, x+w-2, y+w-2);
 232                         g.drawLine(x+w-2, y, x,     y+w-2);
 233                         g.drawLine(x+1,   y, x+w-1, y+w-2);
 234                         g.drawLine(x+w-1, y, x+1,   y+w-2);
 235                     } else {
 236                         x += 2; y++; w -= 2;
 237                         g.drawLine(x,     y,   x+w-1, y+w-1);
 238                         g.drawLine(x+w-1, y,   x,     y+w-1);
 239                         g.drawLine(x+1,   y,   x+w-1, y+w-2);
 240                         g.drawLine(x+w-2, y,   x,     y+w-2);
 241                         g.drawLine(x,     y+1, x+w-2, y+w-1);
 242                         g.drawLine(x+w-1, y+1, x+1,   y+w-1);
 243                         for (int i = 4; i <= lineWidth; i++) {
 244                             g.drawLine(x+i-2,   y,     x+w-1,   y+w-i+1);
 245                             g.drawLine(x,       y+i-2, x+w-i+1, y+w-1);
 246                             g.drawLine(x+w-i+1, y,     x,       y+w-i+1);
 247                             g.drawLine(x+w-1,   y+i-2, x+i-2,   y+w-1);
 248                         }
 249                     }
 250                 } else if (part == Part.WP_MINBUTTON) {
 251                     g.fillRect(x, y+h-thickness2, w-w/3, thickness2);
 252                 } else if (part == Part.WP_MAXBUTTON) {
 253                     g.fillRect(x, y, w, thickness2);
 254                     g.fillRect(x, y, thickness, h);
 255                     g.fillRect(x+w-thickness, y, thickness, h);
 256                     g.fillRect(x, y+h-thickness, w, thickness);
 257                 } else if (part == Part.WP_RESTOREBUTTON) {
 258                     g.fillRect(x+w/3, y, w-w/3, thickness2);
 259                     g.fillRect(x+w/3, y, thickness, h/3);
 260                     g.fillRect(x+w-thickness, y, thickness, h-h/3);
 261                     g.fillRect(x+w-w/3, y+h-h/3-thickness, w/3, thickness);
 262 
 263                     g.fillRect(x, y+h/3, w-w/3, thickness2);
 264                     g.fillRect(x, y+h/3, thickness, h-h/3);
 265                     g.fillRect(x+w-w/3-thickness, y+h/3, thickness, h-h/3);
 266                     g.fillRect(x, y+h-thickness, w-w/3, thickness);
 267                 }
 268             }
 269         }
 270 
 271         public int getIconWidth() {
 272             int width;
 273             if (XPStyle.getXP() != null) {
 274                 // Fix for XP bug where sometimes these sizes aren't updated properly
 275                 // Assume for now that height is correct and derive width using the
 276                 // ratio from the uxtheme part
 277                 width = UIManager.getInt("InternalFrame.titleButtonHeight") -2;
 278                 Dimension d = XPStyle.getPartSize(Part.WP_CLOSEBUTTON, State.NORMAL);
 279                 if (d != null && d.width != 0 && d.height != 0) {
 280                     width = (int) ((float) width * d.width / d.height);
 281                 }
 282             } else {
 283                 width = UIManager.getInt("InternalFrame.titleButtonWidth") -2;
 284             }
 285             if (XPStyle.getXP() != null) {
 286                 width -= 2;
 287             }
 288             return width;
 289         }
 290 
 291         public int getIconHeight() {
 292             int height = UIManager.getInt("InternalFrame.titleButtonHeight")-4;
 293             return height;
 294         }
 295     }
 296 
 297 
 298 
 299         private static class ResizeIcon implements Icon, Serializable {
 300             public void paintIcon(Component c, Graphics g, int x, int y) {
 301                 g.setColor(UIManager.getColor("InternalFrame.resizeIconHighlight"));
 302                 g.drawLine(0, 11, 11, 0);
 303                 g.drawLine(4, 11, 11, 4);
 304                 g.drawLine(8, 11, 11, 8);
 305 
 306                 g.setColor(UIManager.getColor("InternalFrame.resizeIconShadow"));
 307                 g.drawLine(1, 11, 11, 1);
 308                 g.drawLine(2, 11, 11, 2);
 309                 g.drawLine(5, 11, 11, 5);
 310                 g.drawLine(6, 11, 11, 6);
 311                 g.drawLine(9, 11, 11, 9);
 312                 g.drawLine(10, 11, 11, 10);
 313             }
 314             public int getIconWidth() { return 13; }
 315             public int getIconHeight() { return 13; }
 316         };
 317 
 318     private static class CheckBoxIcon implements Icon, Serializable
 319     {
 320         final static int csize = 13;
 321         public void paintIcon(Component c, Graphics g, int x, int y) {
 322             JCheckBox cb = (JCheckBox) c;
 323             ButtonModel model = cb.getModel();
 324             XPStyle xp = XPStyle.getXP();
 325 
 326             if (xp != null) {
 327                 State state;
 328                 if (model.isSelected()) {
 329                     state = State.CHECKEDNORMAL;
 330                     if (!model.isEnabled()) {
 331                         state = State.CHECKEDDISABLED;
 332                     } else if (model.isPressed() && model.isArmed()) {
 333                         state = State.CHECKEDPRESSED;
 334                     } else if (model.isRollover()) {
 335                         state = State.CHECKEDHOT;
 336                     }
 337                 } else {
 338                     state = State.UNCHECKEDNORMAL;
 339                     if (!model.isEnabled()) {
 340                         state = State.UNCHECKEDDISABLED;
 341                     } else if (model.isPressed() && model.isArmed()) {
 342                         state = State.UNCHECKEDPRESSED;
 343                     } else if (model.isRollover()) {
 344                         state = State.UNCHECKEDHOT;
 345                     }
 346                 }
 347                 Part part = Part.BP_CHECKBOX;
 348                 xp.getSkin(c, part).paintSkin(g, x, y, state);
 349             } else {
 350                 // outer bevel
 351                 if(!cb.isBorderPaintedFlat()) {
 352                     // Outer top/left
 353                     g.setColor(UIManager.getColor("CheckBox.shadow"));
 354                     g.drawLine(x, y, x+11, y);
 355                     g.drawLine(x, y+1, x, y+11);
 356 
 357                     // Outer bottom/right
 358                     g.setColor(UIManager.getColor("CheckBox.highlight"));
 359                     g.drawLine(x+12, y, x+12, y+12);
 360                     g.drawLine(x, y+12, x+11, y+12);
 361 
 362                     // Inner top.left
 363                     g.setColor(UIManager.getColor("CheckBox.darkShadow"));
 364                     g.drawLine(x+1, y+1, x+10, y+1);
 365                     g.drawLine(x+1, y+2, x+1, y+10);
 366 
 367                     // Inner bottom/right
 368                     g.setColor(UIManager.getColor("CheckBox.light"));
 369                     g.drawLine(x+1, y+11, x+11, y+11);
 370                     g.drawLine(x+11, y+1, x+11, y+10);
 371 
 372                     // inside box
 373                     if((model.isPressed() && model.isArmed()) || !model.isEnabled()) {
 374                         g.setColor(UIManager.getColor("CheckBox.background"));
 375                     } else {
 376                         g.setColor(UIManager.getColor("CheckBox.interiorBackground"));
 377                     }
 378                     g.fillRect(x+2, y+2, csize-4, csize-4);
 379                 } else {
 380                     g.setColor(UIManager.getColor("CheckBox.shadow"));
 381                     g.drawRect(x+1, y+1, csize-3, csize-3);
 382 
 383                     if((model.isPressed() && model.isArmed()) || !model.isEnabled()) {
 384                         g.setColor(UIManager.getColor("CheckBox.background"));
 385                     } else {
 386                         g.setColor(UIManager.getColor("CheckBox.interiorBackground"));
 387                     }
 388                     g.fillRect(x+2, y+2, csize-4, csize-4);
 389                 }
 390 
 391                 if(model.isEnabled()) {
 392                     g.setColor(UIManager.getColor("CheckBox.foreground"));
 393                 } else {
 394                     g.setColor(UIManager.getColor("CheckBox.shadow"));
 395                 }
 396 
 397                 // paint check
 398                 if (model.isSelected()) {
 399                     g.drawLine(x+9, y+3, x+9, y+3);
 400                     g.drawLine(x+8, y+4, x+9, y+4);
 401                     g.drawLine(x+7, y+5, x+9, y+5);
 402                     g.drawLine(x+6, y+6, x+8, y+6);
 403                     g.drawLine(x+3, y+7, x+7, y+7);
 404                     g.drawLine(x+4, y+8, x+6, y+8);
 405                     g.drawLine(x+5, y+9, x+5, y+9);
 406                     g.drawLine(x+3, y+5, x+3, y+5);
 407                     g.drawLine(x+3, y+6, x+4, y+6);
 408                 }
 409             }
 410         }
 411 
 412         public int getIconWidth() {
 413             XPStyle xp = XPStyle.getXP();
 414             if (xp != null) {
 415                 return xp.getSkin(null, Part.BP_CHECKBOX).getWidth();
 416             } else {
 417                 return csize;
 418             }
 419         }
 420 
 421         public int getIconHeight() {
 422             XPStyle xp = XPStyle.getXP();
 423             if (xp != null) {
 424                 return xp.getSkin(null, Part.BP_CHECKBOX).getHeight();
 425             } else {
 426                 return csize;
 427             }
 428         }
 429     }
 430 
 431     private static class RadioButtonIcon implements Icon, UIResource, Serializable
 432     {
 433         public void paintIcon(Component c, Graphics g, int x, int y) {
 434             AbstractButton b = (AbstractButton) c;
 435             ButtonModel model = b.getModel();
 436             XPStyle xp = XPStyle.getXP();
 437 
 438             if (xp != null) {
 439                 Part part = Part.BP_RADIOBUTTON;
 440                 Skin skin = xp.getSkin(b, part);
 441                 State state;
 442                 int index = 0;
 443                 if (model.isSelected()) {
 444                     state = State.CHECKEDNORMAL;
 445                     if (!model.isEnabled()) {
 446                         state = State.CHECKEDDISABLED;
 447                     } else if (model.isPressed() && model.isArmed()) {
 448                         state = State.CHECKEDPRESSED;
 449                     } else if (model.isRollover()) {
 450                         state = State.CHECKEDHOT;
 451                     }
 452                 } else {
 453                     state = State.UNCHECKEDNORMAL;
 454                     if (!model.isEnabled()) {
 455                         state = State.UNCHECKEDDISABLED;
 456                     } else if (model.isPressed() && model.isArmed()) {
 457                         state = State.UNCHECKEDPRESSED;
 458                     } else if (model.isRollover()) {
 459                         state = State.UNCHECKEDHOT;
 460                     }
 461                 }
 462                 skin.paintSkin(g, x, y, state);
 463             } else {
 464                 // fill interior
 465                 if((model.isPressed() && model.isArmed()) || !model.isEnabled()) {
 466                     g.setColor(UIManager.getColor("RadioButton.background"));
 467                 } else {
 468                     g.setColor(UIManager.getColor("RadioButton.interiorBackground"));
 469                 }
 470                 g.fillRect(x+2, y+2, 8, 8);
 471 
 472 
 473                     // outter left arc
 474                 g.setColor(UIManager.getColor("RadioButton.shadow"));
 475                 g.drawLine(x+4, y+0, x+7, y+0);
 476                 g.drawLine(x+2, y+1, x+3, y+1);
 477                 g.drawLine(x+8, y+1, x+9, y+1);
 478                 g.drawLine(x+1, y+2, x+1, y+3);
 479                 g.drawLine(x+0, y+4, x+0, y+7);
 480                 g.drawLine(x+1, y+8, x+1, y+9);
 481 
 482                 // outter right arc
 483                 g.setColor(UIManager.getColor("RadioButton.highlight"));
 484                 g.drawLine(x+2, y+10, x+3, y+10);
 485                 g.drawLine(x+4, y+11, x+7, y+11);
 486                 g.drawLine(x+8, y+10, x+9, y+10);
 487                 g.drawLine(x+10, y+9, x+10, y+8);
 488                 g.drawLine(x+11, y+7, x+11, y+4);
 489                 g.drawLine(x+10, y+3, x+10, y+2);
 490 
 491 
 492                 // inner left arc
 493                 g.setColor(UIManager.getColor("RadioButton.darkShadow"));
 494                 g.drawLine(x+4, y+1, x+7, y+1);
 495                 g.drawLine(x+2, y+2, x+3, y+2);
 496                 g.drawLine(x+8, y+2, x+9, y+2);
 497                 g.drawLine(x+2, y+3, x+2, y+3);
 498                 g.drawLine(x+1, y+4, x+1, y+7);
 499                 g.drawLine(x+2, y+8, x+2, y+8);
 500 
 501 
 502                 // inner right arc
 503                 g.setColor(UIManager.getColor("RadioButton.light"));
 504                 g.drawLine(x+2,  y+9,  x+3,  y+9);
 505                 g.drawLine(x+4,  y+10, x+7,  y+10);
 506                 g.drawLine(x+8,  y+9,  x+9,  y+9);
 507                 g.drawLine(x+9,  y+8,  x+9,  y+8);
 508                 g.drawLine(x+10, y+7,  x+10, y+4);
 509                 g.drawLine(x+9,  y+3,  x+9,  y+3);
 510 
 511 
 512                  // indicate whether selected or not
 513                 if (model.isSelected()) {
 514                     if (model.isEnabled()) {
 515                         g.setColor(UIManager.getColor("RadioButton.foreground"));
 516                     } else {
 517                         g.setColor(UIManager.getColor("RadioButton.shadow"));
 518                     }
 519                     g.fillRect(x+4, y+5, 4, 2);
 520                     g.fillRect(x+5, y+4, 2, 4);
 521                 }
 522             }
 523         }
 524 
 525         public int getIconWidth() {
 526             XPStyle xp = XPStyle.getXP();
 527             if (xp != null) {
 528                 return xp.getSkin(null, Part.BP_RADIOBUTTON).getWidth();
 529             } else {
 530                 return 13;
 531             }
 532         }
 533 
 534         public int getIconHeight() {
 535             XPStyle xp = XPStyle.getXP();
 536             if (xp != null) {
 537                 return xp.getSkin(null, Part.BP_RADIOBUTTON).getHeight();
 538             } else {
 539                 return 13;
 540             }
 541         }
 542     } // end class RadioButtonIcon
 543 
 544 
 545     private static class CheckBoxMenuItemIcon implements Icon, UIResource, Serializable
 546     {
 547         public void paintIcon(Component c, Graphics g, int x, int y) {
 548             AbstractButton b = (AbstractButton) c;
 549             ButtonModel model = b.getModel();
 550             boolean isSelected = model.isSelected();
 551             if (isSelected) {
 552                 y = y - getIconHeight() / 2;
 553                 g.drawLine(x+9, y+3, x+9, y+3);
 554                 g.drawLine(x+8, y+4, x+9, y+4);
 555                 g.drawLine(x+7, y+5, x+9, y+5);
 556                 g.drawLine(x+6, y+6, x+8, y+6);
 557                 g.drawLine(x+3, y+7, x+7, y+7);
 558                 g.drawLine(x+4, y+8, x+6, y+8);
 559                 g.drawLine(x+5, y+9, x+5, y+9);
 560                 g.drawLine(x+3, y+5, x+3, y+5);
 561                 g.drawLine(x+3, y+6, x+4, y+6);
 562             }
 563         }
 564         public int getIconWidth() { return 9; }
 565         public int getIconHeight() { return 9; }
 566 
 567     } // End class CheckBoxMenuItemIcon
 568 
 569 
 570     private static class RadioButtonMenuItemIcon implements Icon, UIResource, Serializable
 571     {
 572         public void paintIcon(Component c, Graphics g, int x, int y) {
 573             AbstractButton b = (AbstractButton) c;
 574             ButtonModel model = b.getModel();
 575             if (b.isSelected() == true) {
 576                g.fillRoundRect(x+3,y+3, getIconWidth()-6, getIconHeight()-6,
 577                                4, 4);
 578             }
 579         }
 580         public int getIconWidth() { return 12; }
 581         public int getIconHeight() { return 12; }
 582 
 583     } // End class RadioButtonMenuItemIcon
 584 
 585 
 586     private static class MenuItemCheckIcon implements Icon, UIResource, Serializable{
 587         public void paintIcon(Component c, Graphics g, int x, int y) {
 588             /* For debugging:
 589                Color oldColor = g.getColor();
 590             g.setColor(Color.orange);
 591             g.fill3DRect(x,y,getIconWidth(), getIconHeight(), true);
 592             g.setColor(oldColor);
 593             */
 594         }
 595         public int getIconWidth() { return 9; }
 596         public int getIconHeight() { return 9; }
 597 
 598     } // End class MenuItemCheckIcon
 599 
 600     private static class MenuItemArrowIcon implements Icon, UIResource, Serializable {
 601         public void paintIcon(Component c, Graphics g, int x, int y) {
 602             /* For debugging:
 603             Color oldColor = g.getColor();
 604             g.setColor(Color.green);
 605             g.fill3DRect(x,y,getIconWidth(), getIconHeight(), true);
 606             g.setColor(oldColor);
 607             */
 608         }
 609         public int getIconWidth() { return 4; }
 610         public int getIconHeight() { return 8; }
 611 
 612     } // End class MenuItemArrowIcon
 613 
 614     private static class MenuArrowIcon implements Icon, UIResource, Serializable {
 615         public void paintIcon(Component c, Graphics g, int x, int y) {
 616             if (WindowsMenuItemUI.isVistaPainting()) {
 617                 XPStyle xp = XPStyle.getXP();
 618                 State state = State.NORMAL;
 619                 if (c instanceof JMenuItem) {
 620                     state = ((JMenuItem) c).getModel().isEnabled()
 621                     ? State.NORMAL : State.DISABLED;
 622                 }
 623                 Skin skin = xp.getSkin(c, Part.MP_POPUPSUBMENU);
 624                 if (WindowsGraphicsUtils.isLeftToRight(c)) {
 625                     skin.paintSkin(g, x, y, state);
 626                 } else {
 627                     Graphics2D g2d = (Graphics2D)g.create();
 628                     g2d.translate(x + skin.getWidth(), y);
 629                     g2d.scale(-1, 1);
 630                     skin.paintSkin(g2d, 0, 0, state);
 631                     g2d.dispose();
 632                 }
 633             } else {
 634                 g.translate(x,y);
 635                 if( WindowsGraphicsUtils.isLeftToRight(c) ) {
 636                     g.drawLine( 0, 0, 0, 7 );
 637                     g.drawLine( 1, 1, 1, 6 );
 638                     g.drawLine( 2, 2, 2, 5 );
 639                     g.drawLine( 3, 3, 3, 4 );
 640                 } else {
 641                     g.drawLine( 4, 0, 4, 7 );
 642                     g.drawLine( 3, 1, 3, 6 );
 643                     g.drawLine( 2, 2, 2, 5 );
 644                     g.drawLine( 1, 3, 1, 4 );
 645                 }
 646                 g.translate(-x,-y);
 647             }
 648         }
 649         public int getIconWidth() {
 650             if (WindowsMenuItemUI.isVistaPainting()) {
 651                 Skin skin = XPStyle.getXP().getSkin(null, Part.MP_POPUPSUBMENU);
 652                 return skin.getWidth();
 653             } else {
 654                 return 4;
 655             }
 656         }
 657         public int getIconHeight() {
 658             if (WindowsMenuItemUI.isVistaPainting()) {
 659                 Skin skin = XPStyle.getXP().getSkin(null, Part.MP_POPUPSUBMENU);
 660                 return skin.getHeight();
 661             } else {
 662                 return 8;
 663             }
 664         }
 665     } // End class MenuArrowIcon
 666 
 667     static class VistaMenuItemCheckIconFactory
 668            implements MenuItemCheckIconFactory {
 669         private static final int OFFSET = 3;
 670 
 671         public Icon getIcon(JMenuItem component) {
 672             return new VistaMenuItemCheckIcon(component);
 673         }
 674 
 675         public boolean isCompatible(Object icon, String prefix) {
 676             return icon instanceof VistaMenuItemCheckIcon
 677               && ((VistaMenuItemCheckIcon) icon).type == getType(prefix);
 678         }
 679 
 680         public Icon getIcon(String type) {
 681             return new VistaMenuItemCheckIcon(type);
 682         }
 683 
 684         static int getIconWidth() {
 685             return XPStyle.getXP().getSkin(null, Part.MP_POPUPCHECK).getWidth()
 686                 + 2 * OFFSET;
 687         }
 688 
 689         private static Class<? extends JMenuItem> getType(Component c) {
 690             Class<? extends JMenuItem> rv = null;
 691             if (c instanceof JCheckBoxMenuItem) {
 692                 rv = JCheckBoxMenuItem.class;
 693             } else if (c instanceof JRadioButtonMenuItem) {
 694                 rv = JRadioButtonMenuItem.class;
 695             } else if (c instanceof JMenu) {
 696                 rv = JMenu.class;
 697             } else if (c instanceof JMenuItem) {
 698                 rv = JMenuItem.class;
 699             }
 700             return rv;
 701         }
 702 
 703         private static Class<? extends JMenuItem> getType(String type) {
 704             Class<? extends JMenuItem> rv = null;
 705             if (type == "CheckBoxMenuItem") {
 706                 rv = JCheckBoxMenuItem.class;
 707             } else if (type == "RadioButtonMenuItem") {
 708                 rv = JRadioButtonMenuItem.class;
 709             } else if (type == "Menu") {
 710                 rv = JMenu.class;
 711             } else if (type == "MenuItem") {
 712                 rv = JMenuItem.class;
 713             } else {
 714                 // this should never happen
 715                 rv = JMenuItem.class;
 716             }
 717             return rv;
 718         }
 719 
 720         /**
 721          * CheckIcon for JMenuItem, JMenu, JCheckBoxMenuItem and
 722          * JRadioButtonMenuItem.
 723          * Note: to be used on Vista only.
 724          */
 725         private static class VistaMenuItemCheckIcon
 726               implements Icon, UIResource, Serializable {
 727 
 728             private final JMenuItem menuItem;
 729             private final Class<? extends JMenuItem> type;
 730 
 731             VistaMenuItemCheckIcon(JMenuItem menuItem) {
 732                 this.type = getType(menuItem);
 733                 this.menuItem = menuItem;
 734             }
 735             VistaMenuItemCheckIcon(String type) {
 736                 this.type = getType(type);
 737                 this.menuItem = null;
 738             }
 739 
 740             public int getIconHeight() {
 741                 Icon lafIcon = getLaFIcon();
 742                 if (lafIcon != null) {
 743                     return lafIcon.getIconHeight();
 744                 }
 745                 Icon icon = getIcon();
 746                 int height = 0;
 747                 if (icon != null) {
 748                     height = icon.getIconHeight() + 2 * OFFSET;
 749                 } else {
 750                     Skin skin =
 751                         XPStyle.getXP().getSkin(null, Part.MP_POPUPCHECK);
 752                     height = skin.getHeight() + 2 * OFFSET;
 753                 }
 754                 return height;
 755             }
 756 
 757             public int getIconWidth() {
 758                 Icon lafIcon = getLaFIcon();
 759                 if (lafIcon != null) {
 760                     return lafIcon.getIconWidth();
 761                 }
 762                 Icon icon = getIcon();
 763                 int width = 0;
 764                 if (icon != null) {
 765                     width = icon.getIconWidth() + 2 * OFFSET;
 766                 } else {
 767                     width = VistaMenuItemCheckIconFactory.getIconWidth();
 768                 }
 769                 return width;
 770             }
 771 
 772             public void paintIcon(Component c, Graphics g, int x, int y) {
 773                 Icon lafIcon = getLaFIcon();
 774                 if (lafIcon != null) {
 775                     lafIcon.paintIcon(c, g, x, y);
 776                     return;
 777                 }
 778                 assert menuItem == null || c == menuItem;
 779                 Icon icon = getIcon();
 780                 if (type == JCheckBoxMenuItem.class
 781                       || type == JRadioButtonMenuItem.class) {
 782                     AbstractButton b = (AbstractButton) c;
 783                     if (b.isSelected()) {
 784                         Part backgroundPart = Part.MP_POPUPCHECKBACKGROUND;
 785                         Part part = Part.MP_POPUPCHECK;
 786                         State backgroundState;
 787                         State state;
 788                         if (isEnabled(c, null)) {
 789                             backgroundState =
 790                                 (icon != null) ? State.BITMAP : State.NORMAL;
 791                             state = (type == JRadioButtonMenuItem.class)
 792                               ? State.BULLETNORMAL
 793                               : State.CHECKMARKNORMAL;
 794                         } else {
 795                             backgroundState = State.DISABLEDPUSHED;
 796                             state =
 797                                 (type == JRadioButtonMenuItem.class)
 798                                   ? State.BULLETDISABLED
 799                                   : State.CHECKMARKDISABLED;
 800                         }
 801                         Skin skin;
 802                         XPStyle xp = XPStyle.getXP();
 803                         skin =  xp.getSkin(c, backgroundPart);
 804                         skin.paintSkin(g, x, y,
 805                             getIconWidth(), getIconHeight(), backgroundState);
 806                         if (icon == null) {
 807                             skin = xp.getSkin(c, part);
 808                             skin.paintSkin(g, x + OFFSET, y + OFFSET, state);
 809                         }
 810                     }
 811                 }
 812                 if (icon != null) {
 813                     icon.paintIcon(c, g, x + OFFSET, y + OFFSET);
 814                 }
 815             }
 816             private static WindowsMenuItemUIAccessor getAccessor(
 817                     JMenuItem menuItem) {
 818                 WindowsMenuItemUIAccessor rv = null;
 819                 ButtonUI uiObject = (menuItem != null) ? menuItem.getUI()
 820                         : null;
 821                 if (uiObject instanceof WindowsMenuItemUI) {
 822                     rv = ((WindowsMenuItemUI) uiObject).accessor;
 823                 } else if (uiObject instanceof WindowsMenuUI) {
 824                     rv = ((WindowsMenuUI) uiObject).accessor;
 825                 } else if (uiObject instanceof WindowsCheckBoxMenuItemUI) {
 826                     rv = ((WindowsCheckBoxMenuItemUI) uiObject).accessor;
 827                 } else if (uiObject instanceof WindowsRadioButtonMenuItemUI) {
 828                     rv = ((WindowsRadioButtonMenuItemUI) uiObject).accessor;
 829                 }
 830                 return rv;
 831             }
 832 
 833             private static boolean isEnabled(Component  c, State state) {
 834                 if (state == null && c instanceof JMenuItem) {
 835                     WindowsMenuItemUIAccessor accessor =
 836                         getAccessor((JMenuItem) c);
 837                     if (accessor != null) {
 838                         state = accessor.getState((JMenuItem) c);
 839                     }
 840                 }
 841                 if (state == null) {
 842                     if (c != null) {
 843                         return c.isEnabled();
 844                     } else {
 845                         return true;
 846                     }
 847                 } else {
 848                     return (state != State.DISABLED)
 849                         && (state != State.DISABLEDHOT)
 850                         && (state != State.DISABLEDPUSHED);
 851                 }
 852             }
 853             private Icon getIcon() {
 854                 Icon rv = null;
 855                 if (menuItem == null) {
 856                     return rv;
 857                 }
 858                 WindowsMenuItemUIAccessor accessor =
 859                     getAccessor(menuItem);
 860                 State state = (accessor != null) ? accessor.getState(menuItem)
 861                         : null;
 862                 if (isEnabled(menuItem, null)) {
 863                     if (state == State.PUSHED) {
 864                         rv = menuItem.getPressedIcon();
 865                     } else {
 866                         rv = menuItem.getIcon();
 867                     }
 868                 } else {
 869                     rv = menuItem.getDisabledIcon();
 870                 }
 871                 return rv;
 872             }
 873             /**
 874              * Check if developer changed icon in the UI table.
 875              *
 876              * @return the icon to use or {@code null} if the current one is to
 877              * be used
 878              */
 879             private Icon getLaFIcon() {
 880                 // use icon from the UI table if it does not match this one.
 881                 Icon rv = (Icon) UIManager.getDefaults().get(typeToString(type));
 882                 if (rv instanceof VistaMenuItemCheckIcon
 883                       && ((VistaMenuItemCheckIcon) rv).type == type) {
 884                     rv = null;
 885                 }
 886                 return rv;
 887             }
 888 
 889             private static String typeToString(
 890                     Class<? extends JMenuItem> type) {
 891                 assert type == JMenuItem.class
 892                     || type == JMenu.class
 893                     || type == JCheckBoxMenuItem.class
 894                     || type == JRadioButtonMenuItem.class;
 895                 StringBuilder sb = new StringBuilder(type.getName());
 896                 // remove package name, dot and the first character
 897                 sb.delete(0, sb.lastIndexOf("J") + 1);
 898                 sb.append(".checkIcon");
 899                 return sb.toString();
 900             }
 901         }
 902     } // End class VistaMenuItemCheckIconFactory
 903 }